Reference > Self-Hosting

Docker Installation

Install and run n8n with Docker -- quick start, production Docker Compose setup with PostgreSQL, and configuration.

ReferenceIntermediate3 min read

Quick Start

Run n8n with a single command using the default SQLite database:

docker run -d \
  --name n8n \
  -p 5678:5678 \
  -v n8n_data:/home/node/.n8n \
  docker.n8n.io/n8nio/n8n

Open http://localhost:5678 to access the n8n editor. This setup is suitable for testing and development only.

Production Setup with Docker Compose

For production, use PostgreSQL as the database backend and configure persistent volumes, authentication, and a stable webhook URL.

Create a docker-compose.yml file:

version: "3.8"

services:
  n8n:
    image: docker.n8n.io/n8nio/n8n:latest
    container_name: n8n
    restart: unless-stopped
    ports:
      - "5678:5678"
    environment:
      - N8N_HOST=n8n.example.com
      - N8N_PORT=5678
      - N8N_PROTOCOL=https
      - WEBHOOK_URL=https://n8n.example.com/
      - N8N_EDITOR_BASE_URL=https://n8n.example.com/
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_HOST=postgres
      - DB_POSTGRESDB_PORT=5432
      - DB_POSTGRESDB_DATABASE=n8n
      - DB_POSTGRESDB_USER=n8n
      - DB_POSTGRESDB_PASSWORD=changeme
      - N8N_ENCRYPTION_KEY=your-random-encryption-key
      - EXECUTIONS_DATA_PRUNE=true
      - EXECUTIONS_DATA_MAX_AGE=168
    volumes:
      - n8n_data:/home/node/.n8n
    depends_on:
      postgres:
        condition: service_healthy

  postgres:
    image: postgres:16-alpine
    container_name: n8n-postgres
    restart: unless-stopped
    environment:
      - POSTGRES_DB=n8n
      - POSTGRES_USER=n8n
      - POSTGRES_PASSWORD=changeme
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U n8n"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  n8n_data:
  postgres_data:

Start the stack:

docker compose up -d

Warning: Change default passwords

Replace changeme with strong passwords before deploying. Set N8N_ENCRYPTION_KEY to a random string -- this key encrypts stored credentials. If you lose it, all saved credentials become unrecoverable.

Key Environment Variables

Variable Purpose Example
N8N_HOST Hostname for the n8n instance n8n.example.com
N8N_PROTOCOL http or https https
WEBHOOK_URL Public URL for webhook endpoints https://n8n.example.com/
DB_TYPE Database backend (sqlite or postgresdb) postgresdb
N8N_ENCRYPTION_KEY Encrypts stored credentials Random 32+ character string
EXECUTIONS_DATA_PRUNE Auto-delete old execution data true
EXECUTIONS_DATA_MAX_AGE Hours to retain execution data 168 (7 days)

See the Environment Variables Reference for the full list.

Data Persistence

Two volumes are required for a durable setup:

  • n8n_data -- stores n8n configuration, the SQLite database (if used), and encryption keys.
  • postgres_data -- stores the PostgreSQL database files.

Tip

Back up the postgres_data volume regularly. Use pg_dump inside the container for logical backups, or snapshot the volume at the storage layer.

Reverse Proxy

n8n should sit behind a reverse proxy (Nginx, Caddy, Traefik) that handles TLS termination. Key requirements:

  • Forward the Host header and X-Forwarded-* headers to n8n.
  • Enable WebSocket proxying for the editor's real-time updates (Upgrade and Connection headers).
  • Set WEBHOOK_URL to the public URL served by the proxy so that webhook paths resolve correctly.

A minimal Caddy configuration:

n8n.example.com {
    reverse_proxy n8n:5678
}

Updating

Pull the latest image and recreate the container:

docker compose pull n8n
docker compose up -d n8n

Note

Always check the n8n release notes before upgrading. Major version upgrades may include database migrations or breaking changes.

See Also

Want this running in your stack?

I build production n8n and Cloudflare automation for teams — the same engineering behind HarperFlow. Fixed-price, escrow-protected, US-based.