DEV Community

ShoHost
ShoHost

Posted on

Self-Hosting n8n with Docker Compose: Five Settings to Get Right on Day One

Getting n8n running in Docker takes five minutes. Keeping it running for a year without losing credentials, webhooks or disk space takes a few extra settings that the quick-start skips. Here's a Compose setup with the five I'd set on day one.

The Compose file

services:
  postgres:
    image: postgres:16
    restart: unless-stopped
    environment:
      POSTGRES_USER: n8n
      POSTGRES_PASSWORD: ${PG_PASSWORD}
      POSTGRES_DB: n8n
    volumes:
      - pg_data:/var/lib/postgresql/data

  n8n:
    image: docker.n8n.io/n8nio/n8n
    restart: unless-stopped
    ports:
      - "127.0.0.1:5678:5678"
    environment:
      DB_TYPE: postgresdb
      DB_POSTGRESDB_HOST: postgres
      DB_POSTGRESDB_DATABASE: n8n
      DB_POSTGRESDB_USER: n8n
      DB_POSTGRESDB_PASSWORD: ${PG_PASSWORD}
      N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}
      N8N_HOST: n8n.example.com
      N8N_PROTOCOL: https
      WEBHOOK_URL: https://n8n.example.com/
      GENERIC_TIMEZONE: Asia/Kolkata
      EXECUTIONS_DATA_PRUNE: "true"
      EXECUTIONS_DATA_MAX_AGE: 168
    volumes:
      - n8n_data:/home/node/.n8n
    depends_on:
      - postgres

volumes:
  pg_data:
  n8n_data:
Enter fullscreen mode Exit fullscreen mode

Put PG_PASSWORD and N8N_ENCRYPTION_KEY in a .env file next to it (openssl rand -hex 32 makes a good key), then docker compose up -d.

1. Pin your own encryption key

n8n encrypts every saved credential with N8N_ENCRYPTION_KEY. If you don't set one, it generates a key inside the data volume. Rebuild the container without that volume and every credential becomes unreadable. Set it yourself and back it up somewhere other than the server.

2. Use Postgres, not the default SQLite

SQLite is fine for a test. Once you have busy webhooks and thousands of executions, Postgres handles concurrent writes better and is far easier to back up with pg_dump.

3. Tell n8n its public URL

Behind a reverse proxy, n8n doesn't know its own address, so webhook nodes show localhost:5678 URLs that nothing outside can reach. WEBHOOK_URL fixes that. Bind the port to 127.0.0.1 as above and let Caddy or Nginx handle HTTPS in front.

4. Prune old executions

Every run is stored with its input and output data. Without pruning, the database grows until the disk fills. EXECUTIONS_DATA_MAX_AGE: 168 keeps one week of history; raise it if you need longer audits.

5. Set the timezone

Schedule Trigger nodes use GENERIC_TIMEZONE. Leave it unset and your "9 AM" workflow runs at 9 AM UTC, which is 2:30 PM in India.

Backups and updates

A nightly pg_dump of the n8n database plus a copy of your .env is enough to rebuild the whole instance. To update, run docker compose pull && docker compose up -d, but read the n8n release notes first, because major versions sometimes change node behaviour.

If you'd rather skip the server work

All of the above is yours to maintain: OS patches, Docker updates, backups and HTTPS renewals. If you want a private n8n instance without looking after the box, ShoHost's managed n8n hosting runs each instance in isolated Docker on its own KVM plan, with no per-step execution limits. Support is on WhatsApp (+91 94880 91432) and email (support@shohost.com), 9 AM to 12 midnight IST.

Top comments (0)