Add n8n Docker update guide
Covers version checking, pinned-tag update process, SQLite password reset, and why Arcane may not catch updates when the latest tag lags behind npm releases. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
121
02-selfhosting/services/updating-n8n-docker.md
Normal file
121
02-selfhosting/services/updating-n8n-docker.md
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
---
|
||||||
|
title: "Updating n8n Running in Docker"
|
||||||
|
domain: selfhosting
|
||||||
|
category: services
|
||||||
|
tags: [n8n, docker, update, self-hosting, automation]
|
||||||
|
status: published
|
||||||
|
created: 2026-03-30
|
||||||
|
updated: 2026-03-30
|
||||||
|
---
|
||||||
|
|
||||||
|
# Updating n8n Running in Docker
|
||||||
|
|
||||||
|
n8n's in-app update notification checks against their npm release version, which often gets published before the `latest` Docker Hub tag is updated. This means you may see an update prompt in the UI even though `docker pull` reports the image as current. Pull a pinned version tag instead.
|
||||||
|
|
||||||
|
## Check Current vs Latest Version
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check what's running
|
||||||
|
docker exec n8n-n8n-1 n8n --version
|
||||||
|
|
||||||
|
# Check what npm (n8n's upstream) says is latest
|
||||||
|
docker exec n8n-n8n-1 npm show n8n version
|
||||||
|
```
|
||||||
|
|
||||||
|
If the versions differ, the Docker Hub `latest` tag hasn't caught up yet. Use the pinned version tag.
|
||||||
|
|
||||||
|
## Get the Running Container's Config
|
||||||
|
|
||||||
|
Before stopping anything, capture the full environment so you can recreate the container identically:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker inspect n8n-n8n-1 --format '{{json .Config.Env}}'
|
||||||
|
docker inspect n8n-n8n-1 --format '{{range .Mounts}}{{.Source}} -> {{.Destination}}{{println}}{{end}}'
|
||||||
|
```
|
||||||
|
|
||||||
|
For MajorsHouse, the relevant env vars are:
|
||||||
|
|
||||||
|
```
|
||||||
|
N8N_EDITOR_BASE_URL=https://n8n.majorshouse.com/
|
||||||
|
N8N_PORT=5678
|
||||||
|
TZ=America/New_York
|
||||||
|
N8N_TRUST_PROXY=true
|
||||||
|
GENERIC_TIMEZONE=America/New_York
|
||||||
|
N8N_HOST=n8n.majorshouse.com
|
||||||
|
N8N_PROTOCOL=https
|
||||||
|
WEBHOOK_URL=https://n8n.majorshouse.com/
|
||||||
|
```
|
||||||
|
|
||||||
|
Data volume: `n8n_n8n_data:/home/node/.n8n`
|
||||||
|
|
||||||
|
## Perform the Update
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Pull the specific version (replace 2.14.2 with target version)
|
||||||
|
docker pull docker.n8n.io/n8nio/n8n:2.14.2
|
||||||
|
|
||||||
|
# 2. Stop and remove the old container
|
||||||
|
docker stop n8n-n8n-1 && docker rm n8n-n8n-1
|
||||||
|
|
||||||
|
# 3. Start fresh with the new image and same settings
|
||||||
|
docker run -d \
|
||||||
|
--name n8n-n8n-1 \
|
||||||
|
--restart unless-stopped \
|
||||||
|
-p 5678:5678 \
|
||||||
|
-v n8n_n8n_data:/home/node/.n8n \
|
||||||
|
-e N8N_EDITOR_BASE_URL=https://n8n.majorshouse.com/ \
|
||||||
|
-e N8N_PORT=5678 \
|
||||||
|
-e TZ=America/New_York \
|
||||||
|
-e N8N_TRUST_PROXY=true \
|
||||||
|
-e GENERIC_TIMEZONE=America/New_York \
|
||||||
|
-e N8N_HOST=n8n.majorshouse.com \
|
||||||
|
-e N8N_PROTOCOL=https \
|
||||||
|
-e WEBHOOK_URL=https://n8n.majorshouse.com/ \
|
||||||
|
docker.n8n.io/n8nio/n8n:2.14.2
|
||||||
|
|
||||||
|
# 4. Verify
|
||||||
|
docker exec n8n-n8n-1 n8n --version
|
||||||
|
docker ps --filter name=n8n-n8n-1 --format '{{.Status}}'
|
||||||
|
```
|
||||||
|
|
||||||
|
No restart of Caddy or other services required. Workflows, credentials, and execution history are preserved in the data volume.
|
||||||
|
|
||||||
|
## Reset a Forgotten Admin Password
|
||||||
|
|
||||||
|
n8n uses SQLite at `/home/node/.n8n/database.sqlite` (mapped to `n8n_n8n_data` on the host). Use Python to generate a valid bcrypt hash and update it directly — do **not** use shell variable interpolation, as `$` characters in bcrypt hashes will be eaten.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 -c "
|
||||||
|
import bcrypt, sqlite3
|
||||||
|
pw = b'your-new-password'
|
||||||
|
h = bcrypt.hashpw(pw, bcrypt.gensalt(rounds=10)).decode()
|
||||||
|
db = sqlite3.connect('/var/lib/docker/volumes/n8n_n8n_data/_data/database.sqlite')
|
||||||
|
db.execute(\"UPDATE user SET password=? WHERE email='marcus@majorshouse.com'\", (h,))
|
||||||
|
db.commit()
|
||||||
|
db.close()
|
||||||
|
db2 = sqlite3.connect('/var/lib/docker/volumes/n8n_n8n_data/_data/database.sqlite')
|
||||||
|
row = db2.execute(\"SELECT password FROM user WHERE email='marcus@majorshouse.com'\").fetchone()
|
||||||
|
print('Valid:', bcrypt.checkpw(pw, row[0].encode()))
|
||||||
|
"
|
||||||
|
```
|
||||||
|
|
||||||
|
`Valid: True` confirms the hash is correct. No container restart needed.
|
||||||
|
|
||||||
|
## Why Arcane Doesn't Always Catch It
|
||||||
|
|
||||||
|
[Arcane](https://getarcaneapp.com) watches Docker Hub for image digest changes. When n8n publishes a new release, there's often a delay before the `latest` tag on Docker Hub is updated to match. During that window:
|
||||||
|
|
||||||
|
- n8n's in-app updater (checks npm) reports an update available
|
||||||
|
- `docker pull latest` and Arcane both report the image as current
|
||||||
|
|
||||||
|
Once Docker Hub catches up, Arcane will notify normally. For immediate updates, use pinned version tags as shown above.
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
**Password still rejected after update:** Shell variable interpolation (`$2b`, `$10`, etc.) silently truncates bcrypt hashes when passed as inline SQL strings. Always use the Python script approach above.
|
||||||
|
|
||||||
|
**Container exits immediately after recreate:** Check `docker logs n8n-n8n-1`. Most commonly a missing env var or a volume permission issue.
|
||||||
|
|
||||||
|
**Webhooks not firing after update:** Verify `N8N_TRUST_PROXY=true` is set. Without it, Caddy's `X-Forwarded-For` header causes n8n's rate limiter to drop webhook requests before parsing the body.
|
||||||
|
|
||||||
|
**`npm show n8n version` returns old version:** npm registry cache inside the container. Run `docker exec n8n-n8n-1 npm show n8n version --no-cache` to force a fresh check.
|
||||||
@@ -24,6 +24,7 @@
|
|||||||
* [Deploying Netdata to a New Server](02-selfhosting/monitoring/netdata-new-server-setup.md)
|
* [Deploying Netdata to a New Server](02-selfhosting/monitoring/netdata-new-server-setup.md)
|
||||||
* [Netdata SELinux AVC Denial Monitoring](02-selfhosting/monitoring/netdata-selinux-avc-chart.md)
|
* [Netdata SELinux AVC Denial Monitoring](02-selfhosting/monitoring/netdata-selinux-avc-chart.md)
|
||||||
* [Netdata n8n Enriched Alert Emails](02-selfhosting/monitoring/netdata-n8n-enriched-alerts.md)
|
* [Netdata n8n Enriched Alert Emails](02-selfhosting/monitoring/netdata-n8n-enriched-alerts.md)
|
||||||
|
* [Updating n8n Running in Docker](02-selfhosting/services/updating-n8n-docker.md)
|
||||||
* [Linux Server Hardening Checklist](02-selfhosting/security/linux-server-hardening-checklist.md)
|
* [Linux Server Hardening Checklist](02-selfhosting/security/linux-server-hardening-checklist.md)
|
||||||
* [Standardizing unattended-upgrades with Ansible](02-selfhosting/security/ansible-unattended-upgrades-fleet.md)
|
* [Standardizing unattended-upgrades with Ansible](02-selfhosting/security/ansible-unattended-upgrades-fleet.md)
|
||||||
* [Fail2ban Custom Jail: Apache 404 Scanner Detection](02-selfhosting/security/fail2ban-apache-404-scanner-jail.md)
|
* [Fail2ban Custom Jail: Apache 404 Scanner Detection](02-selfhosting/security/fail2ban-apache-404-scanner-jail.md)
|
||||||
|
|||||||
Reference in New Issue
Block a user