Self-Hosting Docker Setup

I run n8n with Docker in an LXC container.
n8n runs in worker mode, which means that at least two containers are started rather than just one.

The first container handles the web UI and delegates pipeline runs.
The second container only executes pipeline runs.
If a pipeline is started manually in the web UI, it runs through the web UI container. The worker container is configured to execute up to four pipelines in parallel.

Worker mode requires a Redis server to distribute job data.
Redis is the third container in my setup.

Because my n8n instance needs to access services with custom SSL certificates, I mounted my own CA certificate in the containers.

I moved the n8n database to a Postgres server. Since I already run a Postgres server on my network, I do not need a separate database container in this Docker setup.

The docker-compose.yml File

x-n8n: &service-n8n
  image: n8nio/n8n:1.74.3
  env_file: n8n.env
  networks:
    - default
  user: node
  volumes:
    - n8n-data:/home/node/.n8n
    - "./MuenchCA.pem:/MuenchCA.pem:ro"
  restart: unless-stopped

services:

  n8n:
    <<: *service-n8n
    container_name: n8n
    ports:
      - 5678:5678
    depends_on:
      redis:
        condition: service_healthy

  n8n_worker:
    <<: *service-n8n
    container_name: n8n_worker
    command: worker --concurrency=6
    depends_on:
      - n8n

  # Webhook container is starting but not working.
  # Ever webhook call results in a 404 http status.
  #n8n_webhook:
  #  <<: *service-n8n
  #  container_name: n8n_webhook
  #  command: webhook
  #  depends_on:
  #    - n8n

  redis:
    container_name: n8n_redis
    image: redis:7-alpine
    restart: unless-stopped
    networks:
      - default
    volumes:
      - redis-data:/data
    healthcheck:
      test: ['CMD', 'redis-cli', 'ping']
      interval: 5s
      timeout: 5s
      retries: 10

volumes:
  n8n-data:
  redis-data:

My .n8n.env File

(Sensitive parameters have been masked)

DB_TYPE=postgresdb
DB_POSTGRESDB_DATABASE=n8n
DB_POSTGRESDB_HOST=postgres.muench.lan
DB_POSTGRESDB_PORT=5432
DB_POSTGRESDB_USER=n8n
DB_POSTGRESDB_PASSWORD=xxxxxxxxxxxxxxxxxxxxxxxxxxxx
DB_POSTGRESDB_SCHEMA=n8n
DB_POSTGRESDB_SSL_REJECT_UNAUTHORIZED=true

EXECUTIONS_MODE=queue
N8N_DISABLE_PRODUCTION_MAIN_PROCESS=false
N8N_CONCURRENCY_PRODUCTION_LIMIT=20

# https://docs.n8n.io/hosting/scaling/execution-data/#reduce-saved-data -> in hours
EXECUTIONS_DATA_PRUNE=true
EXECUTIONS_DATA_MAX_AGE=168
EXECUTIONS_DATA_PRUNE_MAX_COUNT=10000

QUEUE_BULL_REDIS_HOST=redis
QUEUE_HEALTH_CHECK_ACTIVE=true

N8N_BASIC_AUTH_ACTIVE=true
N8N_BASIC_AUTH_USER=xxxxxxxxxxxxxxxxxxxxxxxxxxxx
N8N_BASIC_AUTH_PASSWORD=xxxxxxxxxxxxxxxxxxxxxxxxxxxx
N8N_ENCRYPTION_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxx
N8N_DIAGNOSTICS_ENABLED=false
N8N_HOST=foo.example.com
N8N_PORT=5678
N8N_PROTOCOL=https
NODE_OPTIONS=--max_old_space_size=4096
NODE_ENV=production
WEBHOOK_URL=https://foo.example.com
GENERIC_TIMEZONE=Europe/Berlin
TZ=Europe/Berlin
# required to get DB SSL connection running
NODE_EXTRA_CA_CERTS=/MuenchCA.pem

# Install custom package dependencies
#N8N_CUSTOM_EXTENSIONS=/home/node/.n8n/custom
N8N_REINSTALL_MISSING_PACKAGES=true
N8N_COMMUNITY_PACKAGES_ENABLED=true

# Trust traefik proxy -> See: https://community.n8n.io/t/x-forwarded-for-header-is-set-but-the-express-trust-proxy-s/51208/6
EXPRESS_TRUST_PROXY=true
N8N_PROXY_HOPS=1

N8N_LOG_LEVEL=debug