Skip to content

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.

On your own machine, with no proxy, domain or certificate. From apps/n8n/:

Terminal window
cp .env.local.example .env.local
# The secrets ship empty; generate the ones this stack needs
echo "N8N_ENCRYPTION_KEY=$(openssl rand -hex 32)" >> .env.local
mkdir -p volumes/local/data volumes/local/files
sudo chown -R 1000:1000 volumes/local/data volumes/local/files
docker compose -f docker-compose.local.yml --env-file .env.local up -d

Then open http://localhost:5678. Stop it again with the same command and down.

From apps/n8n/:

  1. Copy the environment file and set APP_TRAEFIK_HOST and TZ:

    Terminal window
    cp .env.example .env
  2. 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 .secrets
    openssl rand -hex 32 > .secrets/n8n_encryption_key.txt

    Copy this file somewhere off the host now, not later.

  3. Create the volumes and hand them to the user n8n runs as:

    Terminal window
    mkdir -p volumes/data volumes/files
    sudo chown -R 1000:1000 volumes/data volumes/files
  4. Start it:

    Terminal window
    docker compose up -d
  5. 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.

Terminal window
docker compose ps # one service, running
curl -fsSI https://<APP_TRAEFIK_HOST>/healthz # 200

Then 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.

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.

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.

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.

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.

n8n ships breaking changes in minor bumps.

  1. Read the release notes for the versions you are crossing.

  2. Stop the container and copy the data directory and the key:

    Terminal window
    docker compose stop n8n-app
    tar czf n8n-backup-$(date +%Y%m%d).tgz volumes/ .secrets/n8n_encryption_key.txt
  3. Raise APP_TAG in .env, then:

    Terminal window
    docker compose pull && docker compose up -d
    docker compose logs n8n-app --follow
  4. 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.

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.