Why Self-Host n8n?
n8n Cloud starts at $20/month with limits on active workflows and executions. On a self-hosted VPS, you get unlimited everything for the cost of the server โ as low as โฌ3.5/month from Hetzner. For freelancers and agencies running dozens of client workflows, self-hosting saves hundreds of euros per month.
Additional benefits of self-hosting:
- Data sovereignty โ your workflow data stays on your server (critical for GDPR compliance)
- No execution limits โ run millions of workflows without throttling
- Custom environment variables โ store API keys and secrets directly on the server
- Full control โ install community nodes, customize configuration, debug logs
- Multiple instances โ run separate n8n instances for different clients
Choosing a VPS Provider
For most n8n use cases, any of these providers work well:
- Hetzner (recommended) โ CX11: 2GB RAM, 1 vCPU, 20GB SSD = โฌ3.49/month. Best price/performance in Europe.
- DigitalOcean โ Basic Droplet: 1GB RAM = $6/month. Excellent documentation and support.
- Vultr โ 1GB RAM = $6/month. Good global network.
- Oracle Cloud Free Tier โ ARM instance with 1GB RAM = completely free. Great for personal use.
Choose a datacenter location close to your clients. European clients โ Frankfurt or Amsterdam. US clients โ New York or San Francisco. Latency matters for webhook response times.
Initial Server Setup (Ubuntu 22.04)
Once you have your VPS, SSH in and run these initial setup commands:
# Connect to your server
ssh root@YOUR_SERVER_IP
# Update the system
apt update && apt upgrade -y
# Create a non-root user (security best practice)
adduser n8nadmin
usermod -aG sudo n8nadmin
# Set up SSH key auth (copy your public key)
mkdir -p /home/n8nadmin/.ssh
cat >> /home/n8nadmin/.ssh/authorized_keys << 'EOF'
YOUR_PUBLIC_KEY_HERE
EOF
chown -R n8nadmin:n8nadmin /home/n8nadmin/.ssh
chmod 700 /home/n8nadmin/.ssh
chmod 600 /home/n8nadmin/.ssh/authorized_keys
# Basic firewall setup
ufw allow OpenSSH
ufw allow 80/tcp
ufw allow 443/tcp
ufw enableInstalling Docker and Docker Compose
# Switch to your non-root user
su - n8nadmin
# Install Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
# Add user to docker group (no sudo needed)
sudo usermod -aG docker $USER
newgrp docker
# Install Docker Compose
sudo apt install docker-compose-plugin -y
# Verify installations
docker --version
docker compose versionDocker Compose File for n8n
Create a directory for your n8n setup and write the Docker Compose config:
mkdir ~/n8n && cd ~/n8n
cat > docker-compose.yml << 'EOF'
version: "3.8"
services:
n8n:
image: docker.n8n.io/n8nio/n8n:latest
restart: always
ports:
- "127.0.0.1:5678:5678"
environment:
- N8N_HOST=n8n.yourdomain.com
- N8N_PORT=5678
- N8N_PROTOCOL=https
- NODE_ENV=production
- WEBHOOK_URL=https://n8n.yourdomain.com/
- GENERIC_TIMEZONE=Europe/Berlin
- TZ=Europe/Berlin
- N8N_ENCRYPTION_KEY=your-random-32-char-secret
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=postgres
- DB_POSTGRESDB_PORT=5432
- DB_POSTGRESDB_DATABASE=n8n
- DB_POSTGRESDB_USER=n8n
- DB_POSTGRESDB_PASSWORD=your-db-password
volumes:
- n8n_data:/home/node/.n8n
depends_on:
postgres:
condition: service_healthy
postgres:
image: postgres:16-alpine
restart: always
environment:
- POSTGRES_USER=n8n
- POSTGRES_PASSWORD=your-db-password
- POSTGRES_DB=n8n
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -h localhost -U n8n"]
interval: 5s
timeout: 5s
retries: 10
volumes:
n8n_data:
postgres_data:
EOFImportant: Replaceyour-random-32-char-secretwith a real random string (useopenssl rand -hex 16). Replaceyour-db-passwordwith a strong password. These are used to encrypt your credentials.
Nginx Reverse Proxy Configuration
# Install Nginx
sudo apt install nginx -y
# Create n8n site config
sudo nano /etc/nginx/sites-available/n8n
# Paste this config:
server {
listen 80;
server_name n8n.yourdomain.com;
location / {
proxy_pass http://127.0.0.1:5678;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket support (required for n8n)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# Timeouts for long-running workflows
proxy_read_timeout 3600;
proxy_send_timeout 3600;
}
}
# Enable the site
sudo ln -s /etc/nginx/sites-available/n8n /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginxSSL with Certbot (Let's Encrypt)
# Install Certbot
sudo apt install certbot python3-certbot-nginx -y
# Get SSL certificate (replace with your domain)
sudo certbot --nginx -d n8n.yourdomain.com
# Follow prompts:
# - Enter email for renewal notifications
# - Agree to terms
# - Choose option 2 (redirect HTTP to HTTPS)
# Certbot automatically updates nginx config and sets up auto-renewal
# Verify auto-renewal
sudo certbot renew --dry-runEnvironment Variables and Security
Instead of hardcoding sensitive values in docker-compose.yml, use a .env file:
# Create .env file in ~/n8n/
cat > .env << 'EOF'
N8N_ENCRYPTION_KEY=your-random-32-char-secret
DB_POSTGRESDB_PASSWORD=your-strong-db-password
N8N_HOST=n8n.yourdomain.com
WEBHOOK_URL=https://n8n.yourdomain.com/
EOF
# Restrict permissions
chmod 600 .env
# Reference in docker-compose.yml using ${VARIABLE_NAME}
# Docker Compose automatically reads .env in the same directoryAutomatic Backup to S3
Set up an n8n workflow to back up all workflows and credentials daily:
- Create a Schedule trigger (daily at 3am)
- HTTP Request to n8n API:
GET /api/v1/workflowswith API key - Convert to JSON
- HTTP Request to AWS S3 or Cloudflare R2 to upload the backup file
- Also use
docker exec n8n-postgres pg_dumpvia Execute Command node for DB backup
For simpler backups without S3, just schedule a cron job on the server:
# Add to crontab (crontab -e)
# Daily backup at 3am
0 3 * * * docker exec n8n-n8n-1 n8n export:workflow --all --output=/home/node/.n8n/backup-$(date +%Y%m%d).jsonStarting and Managing n8n
# Start n8n
cd ~/n8n
docker compose up -d
# View logs
docker compose logs -f n8n
# Stop n8n
docker compose down
# Update to latest n8n version
docker compose pull
docker compose up -d
# Check n8n status
docker compose psMonitoring and Updates
For production setups, add basic monitoring:
- UptimeRobot (free) โ monitors your n8n URL and alerts via email/Telegram if down
- n8n Error Workflow โ create a global error handler workflow that sends you a Telegram message when any workflow fails
- n8n built-in metrics โ enable with
N8N_METRICS=trueenvironment variable
# In your n8n environment variables, add:
N8N_METRICS=true
N8N_METRICS_PREFIX=n8n_
# Access metrics at: https://n8n.yourdomain.com/metrics
# Scrape with Prometheus / view in GrafanaYour self-hosted n8n is now production-ready. You have a fully functional automation server that costs under โฌ5/month and can run unlimited workflows. Master n8n automation with our AI Chatbot course (โฌ59) which covers building client-ready automations from scratch.