Tutorials · 8/2/2026 · Affiliate links may earn us a commission.

Self-Hosting n8n With Docker Compose: Production Setup Guide (2026)

A production-grade n8n self-hosting walkthrough: VPS sizing, Docker Compose with PostgreSQL, HTTPS, backups, and updates — plus when to just pay for n8n Cloud.

This post contains affiliate links. If you buy through them, we may earn a commission at no extra cost to you. See our affiliate disclosure for details.

Short answer: a production-ready self-hosted n8n needs a ~$5–15/month VPS (2 vCPU / 4 GB RAM), Docker Compose, PostgreSQL instead of the default SQLite, a reverse proxy for HTTPS, and a backup script for the database plus the encryption key. That stack gives you unlimited workflow executions for the price of a coffee — the reason self-hosted n8n is the endgame for automation-heavy teams. Total setup time: roughly 30–60 minutes if you’re comfortable in a Linux terminal.

This guide reflects common production patterns and n8n’s documentation as of August 2026. It’s a setup walkthrough, not a benchmark — we cite published sizing guidance rather than our own load tests.

Should you self-host at all?

Do the honest math first (full numbers in our n8n vs Zapier pricing breakdown):

n8n Cloud Startern8n Cloud ProSelf-hosted
Price (Aug 2026)~$20–24/mo~$50–60/mo~$5–15/mo VPS
Executions2,500/mo, hard stop10,000/mo, hard stopUnlimited
MaintenanceNoneNoneYours: updates, backups, security
Uptime responsibilityn8n’sn8n’sYours

Self-host if: you (or someone on staff) can run docker compose without googling every flag, your volume exceeds Cloud tiers, or you have data-residency/compliance needs — self-hosting is the backbone of HIPAA-compliant automation. Pay for Cloud if: nobody wants to own a server. A $50/month bill is cheaper than a broken automation stack nobody can fix. The Community Edition is free for internal business use under n8n’s fair-code Sustainable Use License.

Step 1: Get a VPS and harden it

Published sizing guidance converges on: 2 GB RAM minimum for light personal use; 2 vCPU / 4 GB RAM / 40 GB SSD as the production sweet spot for an SMB running n8n + PostgreSQL + a reverse proxy. Undersized RAM is the most common cause of mysterious workflow deaths (the kernel OOM-killing your container).

Any reputable provider works — Hetzner (its 4 GB ARM instance runs around €4–5/month), DigitalOcean, Vultr, Contabo. Pick Ubuntu 24.04 or Debian 12. Then, before anything else:

# create a non-root user with SSH keys, then:
sudo apt update && sudo apt upgrade -y
sudo apt install -y ufw
sudo ufw allow OpenSSH && sudo ufw allow 80 && sudo ufw allow 443
sudo ufw enable
# install Docker Engine + the compose plugin (docs.docker.com/engine/install)

Point a DNS A record (e.g. n8n.yourdomain.com) at the server’s IP now so certificates work in step 3.

Step 2: Docker Compose with PostgreSQL

n8n defaults to SQLite, which is fine for a laptop and wrong for production: file-level locking blocks concurrent writes, and unclean shutdowns can corrupt the database. PostgreSQL adds about five minutes to setup and removes a future migration.

Create a project directory with a .env file:

POSTGRES_PASSWORD=<long-random-string>
N8N_ENCRYPTION_KEY=<long-random-string>   # openssl rand -hex 32
N8N_HOST=n8n.yourdomain.com
GENERIC_TIMEZONE=America/New_York

And a docker-compose.yml:

services:
  postgres:
    image: postgres:16
    restart: unless-stopped
    environment:
      POSTGRES_USER: n8n
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: n8n
    volumes:
      - pg_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U n8n"]
      interval: 10s
      retries: 5

  n8n:
    image: docker.n8n.io/n8nio/n8n:latest   # pin a version in production
    restart: unless-stopped
    ports:
      - "127.0.0.1:5678:5678"
    environment:
      DB_TYPE: postgresdb
      DB_POSTGRESDB_HOST: postgres
      DB_POSTGRESDB_USER: n8n
      DB_POSTGRESDB_PASSWORD: ${POSTGRES_PASSWORD}
      DB_POSTGRESDB_DATABASE: n8n
      N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}
      N8N_HOST: ${N8N_HOST}
      WEBHOOK_URL: https://${N8N_HOST}/
      GENERIC_TIMEZONE: ${GENERIC_TIMEZONE}
    depends_on:
      postgres:
        condition: service_healthy
    volumes:
      - n8n_data:/home/node/.n8n

volumes:
  pg_data:
  n8n_data:
  caddy_data:

Two deliberate choices here: the port binds to 127.0.0.1 only (the reverse proxy is the sole public entrance), and N8N_ENCRYPTION_KEY is set explicitly — n8n encrypts stored credentials with it. Lose that key and every saved credential becomes unrecoverable. Back it up somewhere that isn’t this server. In production, pin the image to a specific version tag instead of latest.

Run docker compose up -d, then confirm both containers are healthy with docker compose ps.

Step 3: HTTPS with a reverse proxy

Webhooks are the point of n8n, and webhook providers require HTTPS. The lowest-effort option is Caddy, which handles Let’s Encrypt certificates automatically. Add to your compose file:

  caddy:
    image: caddy:2
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data

With a two-line Caddyfile:

n8n.yourdomain.com {
    reverse_proxy n8n:5678
}

(Remove the 127.0.0.1 port mapping from the n8n service when Caddy sits in the same compose network.) Nginx + certbot works equally well if that’s your habit. Visit https://n8n.yourdomain.com, create the owner account, and you’re live.

Step 4: Backups — the step everyone skips

Your automation stack becomes business-critical faster than you expect. Cron two things nightly:

# database dump
docker compose exec -T postgres pg_dump -U n8n n8n | gzip > /backups/n8n-$(date +%F).sql.gz

Plus a copy of your .env (containing the encryption key) stored off-server — object storage, another machine, anywhere but here. A database dump without the encryption key restores workflows but not credentials. Test a restore once; an untested backup is a hope, not a backup.

Step 5: Updating

n8n releases frequently. The routine: read the release notes, take a fresh backup, bump the pinned version in your compose file, then:

docker compose pull && docker compose up -d

Skim the notes especially before major-version jumps — breaking changes to nodes do happen.

Operational gotchas worth knowing

  • Prune execution history. Set EXECUTIONS_DATA_MAX_AGE (e.g. 168 hours) or Postgres will grow unbounded on busy instances.
  • Webhooks beat polling. Polling triggers run constantly whether or not there’s data. On self-hosted this wastes CPU rather than money, but webhook-first design keeps a small VPS fast.
  • Monitor something. Even a free uptime pinger against your n8n URL beats discovering your automations died last Tuesday.
  • Restrict the editor UI. The n8n editor is an admin panel to your entire integration surface — every stored credential can be exercised from it. Beyond a strong owner password, consider putting the UI behind a VPN, IP allowlist, or an authenticating proxy, and enable two-factor authentication in n8n’s user settings. Webhook endpoints must stay public, but the editor doesn’t have to be.
  • Watch disk, not just RAM. Between execution history, Postgres WAL files, and Docker image layers, a neglected 20 GB disk fills quietly. A monthly docker system prune and the execution-age cap above keep a 40 GB disk effectively permanent.
  • Queue mode exists for scale — separate worker containers and Redis — but a single instance on 4 GB RAM covers the vast majority of small-business workloads. Don’t build it until you need it.

When we don’t recommend self-hosting n8n

  • No one owns the server. Backups, updates, and 2 a.m. debugging are recurring costs paid in attention. If that’s nobody’s job, use n8n Cloud — or skip servers entirely with Make (see our Make review).
  • You only run a handful of light automations. A $20/month Cloud Starter or Make’s ~$9 Core plan is simpler than owning infrastructure to save $10.
  • Your team lives in Zapier and it’s working. Migration has real costs; if the bill is fine, stay. When the bill isn’t fine, start with why Zapier gets expensive and compare the alternatives before jumping straight to self-hosting.

FAQ

Is self-hosted n8n really free for commercial use? Yes, for running your own business’s automations — the Community Edition ships under n8n’s fair-code Sustainable Use License. What you can’t do is resell hosted n8n as a product. Your only costs are the server and your time.

What VPS specs do I need? 2 GB RAM runs light workloads; 2 vCPU / 4 GB RAM / 40 GB SSD is the production sweet spot for small-business use, per current published sizing guidance. That’s $5–15/month at mainstream providers as of August 2026.

Can I start with SQLite and switch to PostgreSQL later? You can, but the cutover is annoying enough that starting on Postgres — five extra minutes on day one — is the standard recommendation for anything production-bound.

What’s the single most important thing to back up? The N8N_ENCRYPTION_KEY, alongside the database. Workflows restore from a Postgres dump; credentials only decrypt with the original key.

Do self-hosted and Cloud n8n have the same features? The core workflow engine and nodes are the same. Cloud adds managed hosting and some plan-gated collaboration features; certain enterprise features (SSO, environments) are paid on both sides. For solo and small-team use, Community Edition is fully capable.

Bottom line

An afternoon of setup buys you unlimited automation for VPS pocket change — the best cost structure in the entire category, if you’ll actually maintain it. Provision the server, paste the compose file, configure backups before you build your first workflow, and you’re done. Not ready to run a server? n8n Cloud gets you the same engine with zero ops.

Setup patterns and sizing verified against n8n documentation and independent 2026 guides as of August 2026, including Cherry Servers’ requirements guide and Contabo’s Docker VPS guide.

Pros

Clear trade-offs and practical starting points.

Cons

Pricing and features change; verify before buying.

Check current options