Skip to content

Deploy n8n

n8n is an open-source workflow automation tool (Zapier alternative). This guide gets you a production instance with PostgreSQL backend, HTTPS, and the right config for webhooks.

  • n8n at n8n.example.com
  • PostgreSQL for workflow storage
  • Webhook URL configured correctly (n8n needs this right)
  • Backups of workflows + credentials

Stacks → New stack → name n8n:

services:
db:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_DB: n8n
POSTGRES_USER: n8n
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- db:/var/lib/postgresql/data
n8n:
image: n8nio/n8n:latest
restart: unless-stopped
depends_on: [db]
environment:
DB_TYPE: postgresdb
DB_POSTGRESDB_HOST: db
DB_POSTGRESDB_PORT: 5432
DB_POSTGRESDB_DATABASE: n8n
DB_POSTGRESDB_USER: n8n
DB_POSTGRESDB_PASSWORD: ${DB_PASSWORD}
N8N_HOST: n8n.example.com
N8N_PORT: 5678
N8N_PROTOCOL: https
NODE_ENV: production
WEBHOOK_URL: https://n8n.example.com/
GENERIC_TIMEZONE: ${TZ:-Europe/Berlin}
N8N_ENCRYPTION_KEY: ${ENCRYPTION_KEY}
N8N_USER_MANAGEMENT_JWT_SECRET: ${JWT_SECRET}
volumes:
- n8n_data:/home/node/.n8n
volumes:
db:
n8n_data:
  • DB_PASSWORD — random 32 chars
  • ENCRYPTION_KEY — random 32+ chars, encrypts all credentials stored by n8n. If lost, all saved credentials (API keys, OAuth tokens) become unreadable. Back this up separately from the database.
  • JWT_SECRET — random 32+ chars

Deploy the stack. First boot runs DB migrations, takes ~20 seconds.

Stack → Proxy → Add route:

  • Domain: n8n.example.com
  • Target: n8n_n8n_1
  • Port: 5678
  • TLS: Automatic

Caddy needs to pass WebSocket headers for n8n’s live workflow execution view. Caddy does this by default — no config needed.

Visit https://n8n.example.com. n8n redirects to the setup wizard:

  1. Create owner account (email + password)
  2. Skip the optional telemetry / tips setup
  3. Create your first workflow

n8n webhooks land at https://n8n.example.com/webhook/.... Because we set WEBHOOK_URL correctly, the URL shown in each workflow’s trigger is the right external URL to give your integrations.

If webhooks aren’t firing:

  • Verify WEBHOOK_URL env var is set and matches your domain
  • Check that the webhook URL is not the one with /webhook-test/ — that’s the test URL, inactive outside the editor
  • Activate the workflow (toggle in top-right of the editor)

n8n stores workflows + credentials in the PostgreSQL database. The volume n8n_data has the encryption key config and static files.

Backups → Jobs → New job:

  • Stacks: n8n
  • Target: your off-site target
  • Pre-backup hook: PostgreSQL · pg_dumpall
  • Schedule: Daily
  • Retention: Keep last 14

Critical: back up ENCRYPTION_KEY separately (1Password, your password vault). Without it, encrypted credentials in restored backups are useless.

For heavy workflows, n8n supports queue mode (Redis + workers). Extend the compose:

redis:
image: redis:7-alpine
restart: unless-stopped
n8n-worker:
image: n8nio/n8n:latest
command: worker
depends_on: [db, redis]
environment:
# same env as n8n service above, plus:
EXECUTIONS_MODE: queue
QUEUE_BULL_REDIS_HOST: redis
volumes:
- n8n_data:/home/node/.n8n

Then scale workers via Smart Scaling.

Just bump image: n8nio/n8n:<new-version> and redeploy. DB migrations run automatically on start. Always back up before a major version bump.