n8n Docker Deployment: Installation & Configuration Guide


🐳 n8n Docker Hub
Production‑grade containers · Persistent volumes · Reverse proxy ready
n8n Docker Deployment: Installation & Configuration Guide
Docker Compose | Persistent volumes | Environment variables | PostgreSQL | Reverse proxy integration
This guide focuses exclusively on running n8n inside Docker containers for production. You will learn how to set up persistent storage, configure essential environment variables, choose the right database, and integrate a reverse proxy. Every recommendation follows official n8n documentation.



1. Why should you run n8n in Docker for production?

📌 40‑word answer: Docker isolates n8n from the host system, simplifies dependency management, and enables easy version upgrades via image tags. With persistent volumes, your workflows survive container recreation. Docker Compose orchestrates multi‑service setups including PostgreSQL and Redis.

The official n8n Docker image (n8nio/n8n) bundles Node.js, the n8n application, and all core dependencies. Running n8n in a container prevents version conflicts with other software on the host. Container recreation for updates takes seconds, and you can scale workers horizontally by launching additional containers.

Key Docker advantages for n8n:
– Stateless containers + persistent volumes = safe upgrades
– Environment variables configure every aspect without rebuilding
– One command (docker compose up -d) starts the full stack



2. What is the minimal production Docker Compose file for n8n?

📌 40‑word answer: A production Compose file must include a persistent volume for /home/node/.n8n, set N8N_HOST and WEBHOOK_URL, pin a specific image version (not :latest), and expose port 5678 only behind a reverse proxy.
version: '3.8'
services:
  n8n:
    image: n8nio/n8n:1.78.1
    restart: unless-stopped
    environment:
      - N8N_HOST=n8n.yourdomain.com
      - N8N_PROTOCOL=https
      - WEBHOOK_URL=https://n8n.yourdomain.com
      - N8N_ENCRYPTION_KEY=your-strong-64-char-key
      - N8N_USER_FOLDER=/home/node/.n8n
    volumes:
      - n8n_data:/home/node/.n8n
    ports:
      - "127.0.0.1:5678:5678"
volumes:
  n8n_data:

Bind the volume to /home/node/.n8n to store SQLite (if used), credentials, and configuration. Bind port 5678 only to localhost (127.0.0.1) when a reverse proxy runs on the same host. For multi‑node setups, switch to PostgreSQL and use a shared network.



3. Which environment variables are essential for n8n Docker deployments?

📌 40‑word answer: N8N_HOST (public domain), N8N_PROTOCOL=https, WEBHOOK_URL, N8N_ENCRYPTION_KEY, and optionally DB_TYPE/DB_POSTGRESDB_* for PostgreSQL. Without N8N_HOST, webhook URLs become invalid.

n8n reads over 60 environment variables. The most critical ones are:

Variable Purpose Example
N8N_HOST Public domain for n8n n8n.example.com
N8N_PROTOCOL Set to https when behind TLS proxy https
WEBHOOK_URL Base URL for webhook calls (overrides N8N_HOST) https://n8n.example.com
N8N_ENCRYPTION_KEY Master key for credential AES‑256‑CBC random 64‑char string
EXECUTIONS_TIMEOUT Max workflow runtime in seconds 3600 (default)

If you use PostgreSQL, also set DB_TYPE=postgresdb, DB_POSTGRESDB_HOST, DB_POSTGRESDB_PORT, DB_POSTGRESDB_DATABASE, DB_POSTGRESDB_USER, and DB_POSTGRESDB_PASSWORD. The complete reference is available in the official environment variables docs.



4. How do you persist n8n data across container restarts?

📌 40‑word answer: Mount a Docker volume or host directory to /home/node/.n8n. This folder contains the SQLite database (if used), credential encryption config, and workflow templates. Without volume mapping, all data disappears when the container stops.

Docker containers are ephemeral by design. The n8n image writes all persistent data to /home/node/.n8n. By mapping a named volume or a bind mount to that path, you decouple data from the container lifecycle.

volumes:
  - n8n_data:/home/node/.n8n   # named volume
  # OR
  - ./n8n-data:/home/node/.n8n # bind mount (for easy backup)
🗄️ Backup reminder: Regularly back up the content of /home/node/.n8n together with your N8N_ENCRYPTION_KEY. Without the encryption key, even a full volume backup cannot restore credentials.

For PostgreSQL users, backup the database separately using pg_dump. Volume snapshots are also valid but ensure the database is in a consistent state (stop n8n before backing up).



5. How do you connect n8n Docker to an external PostgreSQL database?

📌 40‑word answer: Set DB_TYPE=postgresdb and provide PostgreSQL connection variables (DB_POSTGRESDB_HOST, DB_POSTGRESDB_DATABASE, etc.). n8n automatically migrates the schema on first startup. Use a separate PostgreSQL container or a managed cloud database.

Replace the default SQLite engine with PostgreSQL to enable queue mode and support higher concurrency. A typical Docker Compose stack includes both n8n and PostgreSQL services:

services:
  n8n:
    image: n8nio/n8n:1.78.1
    environment:
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_HOST=postgres
      - DB_POSTGRESDB_PORT=5432
      - DB_POSTGRESDB_DATABASE=n8n
      - DB_POSTGRESDB_USER=n8n
      - DB_POSTGRESDB_PASSWORD=securepass
  postgres:
    image: postgres:15
    environment:
      - POSTGRES_USER=n8n
      - POSTGRES_PASSWORD=securepass
      - POSTGRES_DB=n8n
    volumes:
      - postgres_data:/var/lib/postgresql/data

n8n automatically creates the required tables. Do not manually alter the schema. For migration from SQLite to PostgreSQL, use n8n export:workflow --all and n8n import:workflow after reconfiguring the database connection.



6. How do you configure a reverse proxy (Nginx/Caddy) for an n8n Docker container?

📌 40‑word answer: Run the reverse proxy in a separate container or on the host, forwarding port 443 to n8n’s internal port 5678. Enable WebSocket upgrade headers. Set N8N_PROTOCOL=https inside the n8n container to generate correct webhook URLs.

n8n does not terminate HTTPS. A reverse proxy adds SSL/TLS, improves security, and offloads certificate management. For Nginx, the critical part is upgrading the WebSocket connection:

location / {
    proxy_pass http://n8n:5678;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
}

When using Caddy, automatic HTTPS is built‑in. A simple Caddyfile entry: n8n.yourdomain.com { reverse_proxy n8n:5678 }. Caddy automatically handles WebSocket upgrades. Always set N8N_PROTOCOL=https so n8n knows to generate secure webhook URLs. Full reverse proxy examples are in the official reverse proxy documentation.



7. How do you safely upgrade n8n Docker without downtime?

📌 40‑word answer: Change the image tag to the target version in your Compose file, run docker compose pull && docker compose up -d. Data stays in persistent volumes. Test the new version in staging first and always pin specific tags (e.g., :1.78.1), never :latest.

Never use :latest in production because it changes unpredictably. Instead, refer to the official Docker Hub tags and select a specific version like 1.78.1. Upgrade procedure:

docker compose stop n8n
docker compose pull n8n
docker compose up -d

Because the persistent volume remains unchanged, no data loss occurs. For major version upgrades (e.g., from 0.x to 1.x), read the release notes for potential breaking changes. Rollback by reverting the image tag and restarting.



8. What are common n8n Docker startup errors and how do you fix them?

📌 40‑word answer: Most errors come from missing volumes (data lost), misconfigured N8N_HOST leading to invalid webhook URLs, database connection failures, or permission issues on bind mounts. Check container logs with docker logs n8n.

Run docker logs <container_name> to see real‑time errors. Frequent issues:

  • “ECONNREFUSED” for PostgreSQL → database container not ready; add depends_on with healthcheck.
  • “Invalid webhook URL”N8N_HOST or WEBHOOK_URL not matching the public domain.
  • “Credentials cannot be decrypted”N8N_ENCRYPTION_KEY changed after data was written. Restore original key or restore backup.
  • Permission denied on bind mount → ensure the host directory is owned by UID 1000 (the node user inside the container).
🔍 Pro tip: Start with a clean Docker Compose file and test with SQLite first. Once everything runs, migrate to PostgreSQL. Use docker compose up --scale n8n=2 to test queue mode locally.





⚠️ Disclaimer: This guide is for informational purposes. Always follow official n8n documentation for production environments. Docker configuration requires security best practices (non‑root user, regular updates, secret management). The author is not affiliated with n8n GmbH.


Leave a Reply

Your email address will not be published. Required fields are marked *