Thinking about running n8n on your own infrastructure? This guide walks you through everything you need to self-host n8n securely and reliably in 2025 — from a quick-start Docker Compose setup to production hardening, backups, monitoring, and horizontal scaling with workers.
Why self-host n8n?
Self-hosting n8n gives you full control over data, architecture, and cost. You can integrate internal systems behind a firewall, meet compliance requirements, and scale with predictable spend. With Docker (or Kubernetes), it’s straightforward to deploy and automate updates and resilience.
Prerequisites
- A VM or server (2 vCPU, 4 GB RAM minimum for small teams; add more for heavy workloads).
- Docker and Docker Compose installed (or Kubernetes if you prefer).
- A domain and DNS A/AAAA record (optional but recommended for TLS and webhooks).
- PostgreSQL and Redis for production-grade reliability and queue mode.
Quick start with Docker Compose
Use this production-ready Compose file to start n8n with PostgreSQL, Redis, and queue executions. Replace placeholders (domain, passwords, keys) before you run.
version: "3.8"
services:
n8n:
image: n8nio/n8n:latest
restart: unless-stopped
ports:
- "5678:5678"
environment:
- N8N_HOST=your.domain.com
- N8N_PORT=5678
- N8N_PROTOCOL=https
- WEBHOOK_URL=https://your.domain.com/
- GENERIC_TIMEZONE=UTC
- N8N_ENCRYPTION_KEY=change_me_to_a_long_random_string
- N8N_BASIC_AUTH_ACTIVE=true
- N8N_BASIC_AUTH_USER=admin
- N8N_BASIC_AUTH_PASSWORD=super-strong-password
# Database
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=postgres
- DB_POSTGRESDB_PORT=5432
- DB_POSTGRESDB_DATABASE=n8n
- DB_POSTGRESDB_USER=n8n
- DB_POSTGRESDB_PASSWORD=super-strong-db-password
# Queue mode (recommended for production)
- EXECUTIONS_MODE=queue
- QUEUE_BULL_REDIS_HOST=redis
- QUEUE_BULL_REDIS_PORT=6379
- QUEUE_BULL_REDIS_DB=0
depends_on:
- postgres
- redis
volumes:
- n8n_data:/home/node/.n8n
worker:
image: n8nio/n8n:latest
restart: unless-stopped
depends_on:
- postgres
- redis
environment:
- GENERIC_TIMEZONE=UTC
- N8N_ENCRYPTION_KEY=change_me_to_a_long_random_string
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=postgres
- DB_POSTGRESDB_PORT=5432
- DB_POSTGRESDB_DATABASE=n8n
- DB_POSTGRESDB_USER=n8n
- DB_POSTGRESDB_PASSWORD=super-strong-db-password
- EXECUTIONS_MODE=queue
- QUEUE_BULL_REDIS_HOST=redis
- QUEUE_BULL_REDIS_PORT=6379
- QUEUE_BULL_REDIS_DB=0
command: ["n8n", "worker"]
postgres:
image: postgres:15
restart: unless-stopped
environment:
- POSTGRES_USER=n8n
- POSTGRES_PASSWORD=super-strong-db-password
- POSTGRES_DB=n8n
volumes:
- postgres_data:/var/lib/postgresql/data
redis:
image: redis:7
restart: unless-stopped
command: ["redis-server", "--appendonly", "yes"]
volumes:
- redis_data:/data
volumes:
n8n_data:
postgres_data:
redis_data:
Start the stack:
docker compose up -d
Once up, access n8n at https://your.domain.com (behind a reverse proxy) or http://server-ip:5678 for quick tests.
Enable HTTPS and a reverse proxy
Terminate TLS with Nginx, Caddy, or Traefik and forward to n8n on port 5678. Example Nginx snippet:
server {
server_name your.domain.com;
location / {
proxy_pass http://127.0.0.1:5678;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
listen 443 ssl http2;
ssl_certificate /etc/letsencrypt/live/your.domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your.domain.com/privkey.pem;
}
Production settings checklist
- Use Postgres + Redis + queue mode: Improves reliability, performance, and enables horizontal scaling.
- Set N8N_ENCRYPTION_KEY: Required to encrypt credentials at rest. Keep it secret and consistent across upgrades.
- Basic auth: Protect the editor with N8N_BASIC_AUTH_ACTIVE, user, and password (or put behind SSO).
- Secure webhooks: Always expose via HTTPS and configure
WEBHOOK_URL
to your public domain. - Backups: Back up Postgres, the
~/.n8n
volume, and encryption key regularly. - Pin versions: Use a known-good tag (e.g.,
n8nio/n8n:1.64.0
) and plan upgrades. - Healthchecks and monitoring: Add Docker/K8s healthchecks; ship logs to your stack (e.g., Loki/ELK) and watch CPU/memory/queue depth.
- Restrict access: Firewall 5678 to your proxy; avoid exposing the editor directly to the internet.
Scaling out with workers
In queue mode, you can run multiple workers to process executions in parallel. Simply scale the worker service:
docker compose up -d --scale worker=3
For Kubernetes, run a Deployment for the web (editor + webhook) pod and a separate Deployment for workers, both pointing to the same Postgres and Redis. Use a LoadBalancer/Ingress for HTTPS and Horizontal Pod Autoscaler on CPU/queue length.
Backups and disaster recovery
- Database: Nightly pg_dump and periodic full volume snapshots.
- Volumes: Backup
~/.n8n
(contains credentials, binaries, user data) and encryption key. - Test restores: Regularly restore to a staging environment to verify RTO/RPO.
Security best practices
- Use least-privilege DB credentials and rotate passwords.
- Keep Docker images updated; subscribe to security advisories.
- Disable anonymous telemetry if required by policy.
- Validate all webhook inputs and sanitize outputs.
- Store secrets in environment variables or a secrets manager; never hardcode in workflows.
Common pitfalls to avoid
- Running on SQLite in production (risk of corruption under load).
- Exposing the editor directly to the internet without auth/TLS.
- Skipping backups of the encryption key (you’ll lose access to credentials).
- Not setting
WEBHOOK_URL
, causing external services to call the wrong endpoint.
Conclusion
With Docker, Postgres, and Redis, self-hosting n8n is both powerful and manageable. Start small, follow the checklist above to harden your deployment, and scale workers as your automation footprint grows.
Need a hand running n8n in production or migrating from a single-node setup? Our team can help you get a secure, observable, and scalable n8n environment live fast.