n8n
n8n chains HTTP calls, webhooks and scheduled jobs into workflows you build visually, with a large library of third-party integrations. One container with its own SQLite database.
Last run on a host 9 Nov 2026 · data restored from a backup
Pinned at 2.46.7 (released 9 Nov 2026) · the newest upstream release
In the upstream images: 1 CRITICAL · 23 HIGH with a published fix — per image
To try it: Docker, nothing else. See Try it locally.
To deploy it behind the proxy: Traefik running and a domain.
Try it locally
Section titled “Try it locally”On your own machine, with no proxy, domain or certificate. From apps/n8n/:
cp .env.local.example .env.local
# The secrets ship empty; generate the ones this stack needsecho "N8N_ENCRYPTION_KEY=$(openssl rand -hex 32)" >> .env.local
mkdir -p volumes/local/data volumes/local/filessudo chown -R 1000:1000 volumes/local/data volumes/local/files
docker compose -f docker-compose.local.yml --env-file .env.local up -dThen open http://localhost:5678. Stop it again with the same command and down.
Installation
Section titled “Installation”From apps/n8n/:
-
Copy the environment file and set
APP_TRAEFIK_HOSTandTZ:Terminal window cp .env.example .env -
Generate the encryption key. It encrypts every credential n8n stores — OAuth tokens, API keys, SMTP passwords — and the data directory is unusable without it:
Terminal window mkdir -p .secretsopenssl rand -hex 32 > .secrets/n8n_encryption_key.txtCopy this file somewhere off the host now, not later.
-
Create the volumes and hand them to the user n8n runs as:
Terminal window mkdir -p volumes/data volumes/filessudo chown -R 1000:1000 volumes/data volumes/files -
Start it:
Terminal window docker compose up -d -
Over the VPN, open
https://<APP_TRAEFIK_HOST>and create the owner account. The setup page answers until the owner exists, and whoever reaches it first owns the instance — the closed access policy keeps that to you.
Verify
Section titled “Verify”docker compose ps # one service, runningcurl -fsSI https://<APP_TRAEFIK_HOST>/healthz # 200Then build one workflow with a manual trigger and run it. A workflow that saves and executes confirms the data directory is writable, which the healthcheck does not cover.
Going further
Section titled “Going further”Who can reach it
Section titled “Who can reach it”The stack ships access-vpn, with limit-standard and headers-standard —
VPN-only. n8n holds API tokens for every service it talks to, which makes it a
more valuable target than what it automates. Its own owner account governs every request;
there is no proxy gate in front of it.
Webhooks from outside
Section titled “Webhooks from outside”A webhook called by GitHub, Stripe or any other external service does not reach
n8n behind a VPN-only policy. Reaching them means a second Traefik router with
access-public scoped to /webhook/*. That router is not configured here — adding
it is a deliberate exposure decision, not a setting.
When SQLite is not enough
Section titled “When SQLite is not enough”Under heavy webhook load SQLite becomes the bottleneck. n8n supports PostgreSQL
through DB_TYPE=postgresdb and its related variables, which needs a db
service added to the stack. Upstream documents queue mode and worker services for
throughput beyond a single executor.
Backup
Section titled “Backup”| Database | SQLite inside volumes/data — no server, no dump hook |
| State | volumes/data (workflows, executions, credentials) · volumes/files |
| Also needed | .secrets/n8n_encryption_key.txt, kept separately |
| Quiescing | Required. Copying a live SQLite file can capture a torn state — stop the container or snapshot the filesystem. |
For borgmatic this stack is source_directories only,
with quiescing. There is no database hook to configure.
Execution history is the bulk of volumes/data and the least useful part of it.
If archive size becomes a problem, prune executions inside n8n rather than
excluding the directory — the credentials live there too.
Updates
Section titled “Updates”n8n ships breaking changes in minor bumps.
-
Read the release notes for the versions you are crossing.
-
Stop the container and copy the data directory and the key:
Terminal window docker compose stop n8n-apptar czf n8n-backup-$(date +%Y%m%d).tgz volumes/ .secrets/n8n_encryption_key.txt -
Raise
APP_TAGin.env, then:Terminal window docker compose pull && docker compose up -ddocker compose logs n8n-app --follow -
Open a workflow that uses a stored credential and run it. A migration that left the encryption in place shows up here and nowhere else.
Troubleshooting
Section titled “Troubleshooting”Every credential is suddenly invalid after a restore. The data directory came
back without the matching n8n_encryption_key.txt, and n8n generated a new key
on start. Put the original key back and restart.
n8n refuses to start, complaining about file permissions.
N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS is on and the settings file is
world-readable. Correct the permissions inside volumes/data.
Permission errors writing to the data directory. volumes/data is not owned
by UID 1000. Re-run the chown from step 3.
Repository files
Section titled “Repository files”apps/n8n/README.md— setup, security model, known issuesapps/n8n/UPSTREAM.md— source and upgrade checklist
Official sources
Section titled “Official sources”© 2026 SecDockBlueCode Apache-2.0Site content CC BY-NC 4.0