n8n Self-Hosted: Complete Setup, Security, and Scaling Guide (2025)

n8n hosting - n8nhost.io

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.

Ready to Launch Your First Workflow?

Start your automation journey in under 60 seconds. No credit card required.

You May Also Like