Skip to main content
All postsAutomation Tools

Self-Hosting n8n: A Complete 2026 Setup Guide

Step-by-step guide to deploying n8n on your own infrastructure in 2026 — Docker, environment configuration, SSL, backups, and what to watch for in production.

Zach McMorrough
May 3, 2026 11 min read

Self-hosting n8n gets you full control over your data, predictable costs, and unlimited workflow executions — all for the price of a $15/month VPS. The tradeoff: you're responsible for setup, updates, and keeping the lights on.

This guide walks through a production-ready n8n deployment in about 90 minutes. We use this exact stack for the n8n instances we host on behalf of clients.

Prerequisites

  • A domain name (or subdomain) you control. We'll use n8n.yourcompany.com for examples.
  • A VPS with at least 2 GB RAM and 1 vCPU. DigitalOcean's $12/month Basic droplet is the sweet spot for most teams. AWS Lightsail and Hetzner CX22 work equally well.
  • SSH access to that VPS, with a non-root sudo user configured.
  • About 90 minutes.

Step 1: Server setup (10 min)

SSH into your VPS and install Docker. On Ubuntu 24.04:

sudo apt update && sudo apt upgrade -y
sudo apt install -y docker.io docker-compose-plugin
sudo systemctl enable --now docker
sudo usermod -aG docker $USER
exit  # log out and back in for the group change to apply

Confirm Docker works:

docker run --rm hello-world

Step 2: DNS pointing (5 min)

In your DNS provider, add an A record pointing n8n.yourcompany.com to your VPS's public IP address. Let it propagate (usually 1–5 minutes).

Step 3: Docker Compose configuration (15 min)

Create a working directory and a docker-compose.yml file:

mkdir -p ~/n8n && cd ~/n8n

Paste this into ~/n8n/docker-compose.yml:

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

  n8n:
    image: n8nio/n8n:latest
    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: ${POSTGRES_PASSWORD}
      N8N_HOST: ${N8N_HOST}
      N8N_PORT: 5678
      N8N_PROTOCOL: https
      WEBHOOK_URL: https://${N8N_HOST}/
      GENERIC_TIMEZONE: America/New_York
      N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}
    depends_on:
      - postgres
    volumes:
      - n8n_data:/home/node/.n8n

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

volumes:
  postgres_data:
  n8n_data:
  caddy_data:
  caddy_config:

Create a .env file in the same directory:

cat > .env <<EOF
POSTGRES_PASSWORD=$(openssl rand -hex 24)
N8N_HOST=n8n.yourcompany.com
N8N_ENCRYPTION_KEY=$(openssl rand -hex 24)
EOF
chmod 600 .env

The encryption key is critical — it encrypts your credentials inside n8n. Back this up somewhere secure. If you lose it, every saved credential becomes unreadable.

Step 4: Caddy reverse proxy + auto-SSL (5 min)

Create ~/n8n/Caddyfile:

n8n.yourcompany.com {
    reverse_proxy n8n:5678
}

Caddy will automatically obtain a Let's Encrypt SSL certificate when it starts.

Step 5: Start everything (5 min)

cd ~/n8n
docker compose up -d
docker compose logs -f n8n

You should see n8n start. Once you see Editor is now accessible via: https://n8n.yourcompany.com/, hit Ctrl+C to exit the logs (the container keeps running).

Visit https://n8n.yourcompany.com in your browser. You'll be prompted to create the owner account. Use a real email — n8n uses it for password recovery, and there's no built-in "I forgot my admin password" flow for self-hosted instances.

Step 6: Production hardening

A working n8n instance isn't a production-ready n8n instance. Don't skip these.

Backup the database nightly. Add this to root's crontab:

0 2 * * * cd /home/youruser/n8n && docker compose exec -T postgres pg_dump -U n8n n8n | gzip > /home/youruser/backups/n8n-$(date +\%Y\%m\%d).sql.gz

Rotate to keep the last 30 days. Push to S3 / Backblaze B2 weekly for off-site copies.

Enable basic auth on the editor (separate from the n8n user account):

# Add to the n8n service environment block:
N8N_BASIC_AUTH_ACTIVE: "true"
N8N_BASIC_AUTH_USER: ${BASIC_AUTH_USER}
N8N_BASIC_AUTH_PASSWORD: ${BASIC_AUTH_PASSWORD}

Monitor uptime. Free options: UptimeRobot, BetterStack, or self-hosted Uptime Kuma. Check https://n8n.yourcompany.com/healthz every 60 seconds.

Subscribe to n8n's security advisories at https://github.com/n8n-io/n8n/security/advisories. Critical patches roll out monthly.

Updates

cd ~/n8n
docker compose pull
docker compose up -d

Major-version upgrades occasionally have breaking changes. Always read the release notes first, and test in staging before pulling into production.

When self-hosting isn't worth it

A few cases where n8n Cloud is the better call:

  • You don't have anyone comfortable with Docker or Linux.
  • Your workflow volume is genuinely low (< 1,000 executions/month).
  • Compliance requirements specifically want a managed/SOC2 environment.

For everyone else: self-hosting routinely saves $200–$500/month versus n8n Cloud or Zapier equivalents.

What we do for clients

We host and manage production n8n instances for B2B operations teams who want self-hosted control but don't want to babysit the infrastructure. Everything in this guide, plus monitoring, backup verification, monthly patching, and 24-hour incident response.

If that's interesting, book a 30-minute discovery call and we'll talk through your stack. Or browse the automation catalogue for the workflows we ship most often.

Want us to automate this for you?

Book a 30-minute discovery call — no pressure, no commitment.