Why Self-Host n8n?
n8n Cloud costs $20–120/month depending on executions. A self-hosted n8n instance on a $6–10/month VPS (Hetzner CX22 or DigitalOcean Droplet) runs unlimited workflows, unlimited executions, and stores all your data privately — for roughly the cost of a cup of coffee per month. For SaaS founders, agencies, and developers running serious automation workloads, self-hosting is almost always the right economic decision.
This guide gets you from a blank VPS to a production-ready n8n instance with SSL, a domain, basic authentication, and automatic restarts — in under an hour.
What You Need
- A VPS with at least 2GB RAM (Hetzner CX22 at €3.79/month, DigitalOcean $6/month Basic Droplet, or Vultr $6/month)
- Ubuntu 22.04 LTS (recommended)
- A domain name (or subdomain) pointed to your server’s IP — e.g., n8n.yourdomain.com
- Basic SSH access comfort
Step 1 — Server Initial Setup
SSH into your fresh server and run initial updates:
ssh root@YOUR_SERVER_IP
apt update && apt upgrade -y
apt install -y curl git ufw
Set up a firewall — allow SSH, HTTP, and HTTPS only:
ufw allow ssh
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable
Step 2 — Install Docker and Docker Compose
curl -fsSL https://get.docker.com | sh
apt install -y docker-compose-plugin
systemctl enable docker
systemctl start docker
Verify both are working:
docker --version
docker compose version
Step 3 — Point Your Domain to the Server
In your domain registrar’s DNS settings, add an A record:
- Type: A
- Name: n8n (or @ for root domain)
- Value: YOUR_SERVER_IP
- TTL: 300
Wait 5–15 minutes for DNS propagation. You can check with: nslookup n8n.yourdomain.com
Step 4 — Create the Docker Compose File
Create a directory and the compose file:
mkdir /opt/n8n && cd /opt/n8n
nano docker-compose.yml
Paste this configuration (replace the values in caps):
version: "3.8"
services:
traefik:
image: traefik:v3.0
restart: always
command:
- "--api=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.letsencrypt.acme.tlschallenge=true"
- "--certificatesresolvers.letsencrypt.acme.email=YOUR_EMAIL"
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
- "--entrypoints.web.http.redirections.entryPoint.to=websecure"
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./letsencrypt:/letsencrypt
n8n:
image: n8nio/n8n:latest
restart: always
environment:
- N8N_HOST=YOUR_DOMAIN (e.g. n8n.yourdomain.com)
- N8N_PORT=5678
- N8N_PROTOCOL=https
- WEBHOOK_URL=https://YOUR_DOMAIN/
- GENERIC_TIMEZONE=Asia/Karachi
- N8N_BASIC_AUTH_ACTIVE=true
- N8N_BASIC_AUTH_USER=YOUR_USERNAME
- N8N_BASIC_AUTH_PASSWORD=YOUR_STRONG_PASSWORD
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=postgres
- DB_POSTGRESDB_PORT=5432
- DB_POSTGRESDB_DATABASE=n8n
- DB_POSTGRESDB_USER=n8nuser
- DB_POSTGRESDB_PASSWORD=YOUR_DB_PASSWORD
volumes:
- n8n_data:/home/node/.n8n
depends_on:
- postgres
labels:
- "traefik.enable=true"
- "traefik.http.routers.n8n.rule=Host(`YOUR_DOMAIN`)"
- "traefik.http.routers.n8n.entrypoints=websecure"
- "traefik.http.routers.n8n.tls.certresolver=letsencrypt"
- "traefik.http.services.n8n.loadbalancer.server.port=5678"
postgres:
image: postgres:15
restart: always
environment:
- POSTGRES_USER=n8nuser
- POSTGRES_PASSWORD=YOUR_DB_PASSWORD
- POSTGRES_DB=n8n
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
n8n_data:
postgres_data:
letsencrypt:
Step 5 — Launch n8n
cd /opt/n8n
docker compose up -d
Watch the logs to confirm everything started cleanly:
docker compose logs -f n8n
Within 1–2 minutes, Traefik will obtain a Let’s Encrypt SSL certificate and n8n will be live at https://YOUR_DOMAIN. Login with the basic auth credentials you set.
Step 6 — Production Hardening
Automatic Backups
Your workflows are stored in PostgreSQL. Back up the volume daily with a cron job:
crontab -e
# Add this line:
0 2 * * * docker exec n8n-postgres-1 pg_dump -U n8nuser n8n > /opt/n8n/backups/n8n_$(date +\%Y\%m\%d).sql
Keeping n8n Updated
cd /opt/n8n
docker compose pull
docker compose up -d
Monitoring
Set up a free uptime monitor (UptimeRobot or BetterUptime) pointing to your n8n URL. You’ll get notified if the server goes down. For a $6/month VPS this is sufficient — uptime on Hetzner and DigitalOcean is consistently 99.9%+.
Common Issues and Fixes
- SSL certificate not issuing: DNS hasn’t propagated yet. Wait 15 minutes and run
docker compose restart traefik - n8n won’t start: Check logs with
docker compose logs n8n. Common cause: wrong DB password or port conflict - Webhooks not working: Ensure
WEBHOOK_URLis set correctly tohttps://YOUR_DOMAIN/with the trailing slash - Running out of memory: Enable swap:
fallocate -l 2G /swapfile && chmod 600 /swapfile && mkswap /swapfile && swapon /swapfile
→ n8n Automation Services by Zargham Labs | Hire a SaaS Developer
