n8n is a workflow automation platform that can connect APIs, databases, AI services, and internal tools. A self-hosted instance may contain production credentials and business data, so persistence, encryption, HTTPS, access control, and backups should be part of the first deployment.

Docker Compose configuration

Create a dedicated directory and a .env file containing a stable encryption key:

1
2
3
N8N_HOST=n8n.example.com
N8N_ENCRYPTION_KEY=replace-with-a-long-random-value
TZ=UTC

Never change or lose N8N_ENCRYPTION_KEY after credentials have been saved. Without it, encrypted credentials may become unreadable.

Create compose.yaml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
services:
n8n:
image: docker.n8n.io/n8nio/n8n:2.0.0
container_name: n8n
restart: unless-stopped
environment:
- N8N_HOST=${N8N_HOST}
- N8N_PROTOCOL=https
- N8N_PORT=5678
- WEBHOOK_URL=https://${N8N_HOST}/
- N8N_PROXY_HOPS=1
- N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
- GENERIC_TIMEZONE=${TZ}
- TZ=${TZ}
volumes:
- n8n_data:/home/node/.n8n
expose:
- "5678"

volumes:
n8n_data:

Start and inspect the container:

1
2
docker compose up -d
docker compose logs -f --tail=100 n8n

Using expose keeps port 5678 off the public host interface. Place n8n behind an HTTPS reverse proxy on the same Docker network or publish the port only to 127.0.0.1.

Reverse proxy requirements

Your proxy must forward the original host, protocol, and client address. For Nginx, the core location is:

1
2
3
4
5
6
7
8
9
10
location / {
proxy_pass http://127.0.0.1:5678;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}

Incorrect WEBHOOK_URL, proxy headers, or proxy-hop settings are common reasons test webhooks work but production webhooks point to localhost or use HTTP.

Backups

Back up both the database and the encryption key. With the default SQLite setup, the named volume contains the database and instance data. Stop writes or use an application-consistent method before copying it. Larger teams should evaluate PostgreSQL and test a complete restore regularly.

Exporting workflows is useful, but workflow JSON alone is not a full disaster-recovery backup because credentials, executions, users, and instance configuration live elsewhere.

Security checklist

  • Use HTTPS and restrict editor access with an identity-aware proxy, VPN, or firewall.
  • Run the container as its default non-root user.
  • Keep secrets out of workflow logs and source control.
  • Limit community nodes and review any node that executes code.
  • Configure execution retention so old payloads do not grow forever.
  • Pin versions, read release notes, and back up before upgrades.
  • Protect public webhooks with signatures, tokens, rate limits, and input validation.

Updating n8n

Pull and recreate the service after reviewing breaking changes:

1
2
3
docker compose pull
docker compose up -d
docker compose logs --tail=100 n8n

For important workflows, rehearse upgrades against a restored backup before updating production.