n8n is a powerful workflow automation tool that you can run on your own server. Unlike Zapier or Make, self-hosted n8n has no per-execution fees - pay only for your server.
I've deployed n8n for multiple clients and use it for my own automation needs. In my experience, self-hosting is worth the initial setup effort. This guide walks you through setting up n8n from download to production-ready deployment.
Why Self-Host n8n?
Before we start the installation, here's why you might choose self-hosted over n8n Cloud:
Cost savings: No per-execution fees. Run 100,000 workflows per month for the cost of a $20/month server.
Data privacy: Your data stays on your server. Critical for healthcare, finance, or any sensitive data.
Full control: Customize everything. No vendor limitations.
No vendor lock-in: Your workflows are yours. Export and migrate anytime.
The trade-off: You manage the infrastructure. I found it's surprisingly low-maintenance once set up properly - this guide shows you how.
Prerequisites
Before you download and install n8n, you'll need:
- A server (VPS) with at least 2GB RAM
- Ubuntu 22.04 or newer (this guide uses Ubuntu)
- A domain name pointed to your server
- Basic command line knowledge
- SSH access to your server
Recommended providers:
- DigitalOcean ($12-24/month)
- Hetzner ($5-10/month) - Best value
- Linode ($12-24/month)
- AWS Lightsail ($10-20/month)
Quick Start: n8n Download and Setup
For those who want to get running fast, here's the minimal setup:
# Install Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
# Run n8n
docker run -d \
--name n8n \
--restart always \
-p 5678:5678 \
-v n8n_data:/home/node/.n8n \
n8nio/n8n
Access n8n at http://your-server-ip:5678
This works but isn't production-ready. Keep reading for a proper setup.
Step 1: Prepare Your Server
Update System
sudo apt update && sudo apt upgrade -y
Install Docker
# Download and install Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
# Add your user to docker group
sudo usermod -aG docker $USER
# Log out and back in, then verify
docker --version
Install Docker Compose
sudo apt install docker-compose-plugin -y
# Verify
docker compose version
Configure Firewall
sudo ufw allow 22 # SSH
sudo ufw allow 80 # HTTP
sudo ufw allow 443 # HTTPS
sudo ufw enable
Step 2: Set Up n8n with Docker Compose
Create a directory for n8n:
mkdir -p ~/n8n && cd ~/n8n
Create the Docker Compose file:
nano docker-compose.yml
Paste this configuration:
version: '3.8'
services:
n8n:
image: n8nio/n8n
container_name: n8n
restart: always
ports:
- "5678:5678"
environment:
- N8N_HOST=${N8N_HOST}
- N8N_PORT=5678
- N8N_PROTOCOL=https
- NODE_ENV=production
- WEBHOOK_URL=https://${N8N_HOST}/
- GENERIC_TIMEZONE=${TIMEZONE}
# Security
- N8N_BASIC_AUTH_ACTIVE=true
- N8N_BASIC_AUTH_USER=${N8N_USER}
- N8N_BASIC_AUTH_PASSWORD=${N8N_PASSWORD}
# Database (optional - SQLite by default)
# - DB_TYPE=postgresdb
# - DB_POSTGRESDB_HOST=postgres
# - DB_POSTGRESDB_DATABASE=n8n
# - DB_POSTGRESDB_USER=n8n
# - DB_POSTGRESDB_PASSWORD=${DB_PASSWORD}
volumes:
- n8n_data:/home/node/.n8n
- ./local-files:/files
networks:
- n8n-network
networks:
n8n-network:
volumes:
n8n_data:
Create the environment file:
nano .env
Add your configuration:
N8N_HOST=n8n.yourdomain.com
TIMEZONE=America/New_York
N8N_USER=admin
N8N_PASSWORD=your-secure-password-here
Important: Use a strong password. This protects your entire automation system.
Step 3: Set Up SSL with Caddy
n8n needs HTTPS for webhooks to work reliably. We'll use Caddy as a reverse proxy - it handles SSL certificates automatically.
Add Caddy to your docker-compose.yml:
version: '3.8'
services:
caddy:
image: caddy:2
container_name: caddy
restart: always
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
- caddy_config:/config
networks:
- n8n-network
n8n:
image: n8nio/n8n
container_name: n8n
restart: always
# Remove ports - Caddy handles external access
# ports:
# - "5678:5678"
environment:
- N8N_HOST=${N8N_HOST}
- N8N_PORT=5678
- N8N_PROTOCOL=https
- NODE_ENV=production
- WEBHOOK_URL=https://${N8N_HOST}/
- GENERIC_TIMEZONE=${TIMEZONE}
- N8N_BASIC_AUTH_ACTIVE=true
- N8N_BASIC_AUTH_USER=${N8N_USER}
- N8N_BASIC_AUTH_PASSWORD=${N8N_PASSWORD}
volumes:
- n8n_data:/home/node/.n8n
- ./local-files:/files
networks:
- n8n-network
networks:
n8n-network:
volumes:
n8n_data:
caddy_data:
caddy_config:
Create the Caddyfile:
nano Caddyfile
Add:
n8n.yourdomain.com {
reverse_proxy n8n:5678
}
Replace n8n.yourdomain.com with your actual domain.
Step 4: Start n8n
docker compose up -d
Check that everything is running:
docker compose ps
You should see both caddy and n8n with status "Up".
Access n8n at https://n8n.yourdomain.com
Step 5: Configure n8n
Initial Setup
On first access:
- Log in with the credentials from your .env file
- Create your owner account (this is different from basic auth)
- Set up your first workflow
Essential Settings
Go to Settings → Personal:
- Set your timezone correctly
- Configure your name and email
Go to Settings → Community nodes (optional):
- Enable community nodes for additional integrations
Security Hardening
Add these environment variables for additional security:
environment:
# ... existing vars ...
- N8N_BLOCK_ENV_ACCESS_IN_NODE=true
- N8N_PERSONALIZATION_ENABLED=false
- EXECUTIONS_DATA_PRUNE=true
- EXECUTIONS_DATA_MAX_AGE=168 # 7 days in hours
Step 6: Set Up Backups
Your n8n data is stored in Docker volumes. Set up automatic backups:
Create backup script:
nano ~/n8n/backup.sh
Add:
#!/bin/bash
BACKUP_DIR="/home/$USER/n8n-backups"
DATE=$(date +%Y-%m-%d_%H-%M-%S)
mkdir -p $BACKUP_DIR
# Export workflows
docker exec n8n n8n export:workflow --all --output=/files/workflows-$DATE.json
# Export credentials (encrypted)
docker exec n8n n8n export:credentials --all --output=/files/credentials-$DATE.json
# Backup the volume
docker run --rm \
-v n8n_n8n_data:/data \
-v $BACKUP_DIR:/backup \
alpine tar czf /backup/n8n-data-$DATE.tar.gz -C /data .
# Move exported files
mv ~/n8n/local-files/workflows-$DATE.json $BACKUP_DIR/
mv ~/n8n/local-files/credentials-$DATE.json $BACKUP_DIR/
# Keep only last 7 backups
ls -tp $BACKUP_DIR/*.tar.gz | tail -n +8 | xargs -I {} rm -- {}
ls -tp $BACKUP_DIR/workflows-*.json | tail -n +8 | xargs -I {} rm -- {}
ls -tp $BACKUP_DIR/credentials-*.json | tail -n +8 | xargs -I {} rm -- {}
echo "Backup completed: $DATE"
Make it executable and schedule:
chmod +x ~/n8n/backup.sh
# Add to crontab - daily at 2 AM
(crontab -l 2>/dev/null; echo "0 2 * * * /home/$USER/n8n/backup.sh") | crontab -
Step 7: Set Up Monitoring
Basic Health Check
Add a simple health check script:
nano ~/n8n/health-check.sh
#!/bin/bash
HEALTH=$(curl -s -o /dev/null -w "%{http_code}" https://n8n.yourdomain.com/healthz)
if [ "$HEALTH" != "200" ]; then
echo "n8n is down! Status: $HEALTH" | mail -s "n8n Alert" your@email.com
# Or send to Slack/Discord webhook
fi
Execution Monitoring
Create a workflow in n8n that:
- Runs on schedule (daily)
- Queries the n8n API for failed executions
- Sends alert if failures exceed threshold
Production Configuration
Using PostgreSQL Instead of SQLite
For production with high volume, use PostgreSQL:
services:
postgres:
image: postgres:15
container_name: n8n-postgres
restart: always
environment:
- POSTGRES_USER=n8n
- POSTGRES_PASSWORD=${DB_PASSWORD}
- POSTGRES_DB=n8n
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- n8n-network
n8n:
# ... existing config ...
environment:
# ... existing vars ...
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=postgres
- DB_POSTGRESDB_DATABASE=n8n
- DB_POSTGRESDB_USER=n8n
- DB_POSTGRESDB_PASSWORD=${DB_PASSWORD}
depends_on:
- postgres
Add to .env:
DB_PASSWORD=your-database-password
Queue Mode for High Volume
For many concurrent executions, enable queue mode with Redis:
services:
redis:
image: redis:7
container_name: n8n-redis
restart: always
networks:
- n8n-network
n8n:
environment:
- EXECUTIONS_MODE=queue
- QUEUE_BULL_REDIS_HOST=redis
- QUEUE_HEALTH_CHECK_ACTIVE=true
Resource Limits
Add resource limits to prevent runaway workflows:
n8n:
# ... existing config ...
deploy:
resources:
limits:
memory: 2G
cpus: '2'
reservations:
memory: 512M
Updating n8n
Check Current Version
docker exec n8n n8n --version
Update Process
cd ~/n8n
# Pull latest image
docker compose pull
# Restart with new image
docker compose up -d
# Check logs for issues
docker compose logs -f n8n
Rollback if Needed
# Stop current version
docker compose down
# Use specific version
# Edit docker-compose.yml: image: n8nio/n8n:0.236.0
docker compose up -d
Troubleshooting
n8n Won't Start
Check logs:
docker compose logs n8n
Common issues:
- Port already in use: Change the port in docker-compose.yml
- Permission issues: Check volume permissions
- Memory issues: Increase server RAM or add swap
Webhooks Not Working
Verify:
- SSL is working:
curl -I https://n8n.yourdomain.com - WEBHOOK_URL is correct in .env
- Firewall allows 443
Executions Failing
Check:
- Execution logs in n8n UI
- Docker logs:
docker compose logs -f n8n - Resource usage:
docker stats
Database Connection Issues
For PostgreSQL:
# Check if postgres is running
docker compose ps postgres
# Check connection
docker exec n8n-postgres psql -U n8n -d n8n -c "SELECT 1;"
n8n Download Locations
Official Sources
- Docker Hub:
docker pull n8nio/n8n - GitHub: https://github.com/n8n-io/n8n
- npm:
npm install -g n8n(not recommended for production)
Version Pinning
For production, pin to specific versions:
image: n8nio/n8n:1.20.0
Check releases: https://github.com/n8n-io/n8n/releases
Next Steps
Now that n8n is running:
- Create your first workflow: Start with something simple like a webhook-to-Slack notification
- Import community workflows: Many templates available on n8n.io
- Set up error notifications: Create a workflow that alerts on execution failures
- Document your setup: Keep notes for future maintenance
Related resources:
- n8n automation examples - Practical workflows to build
- Make vs Zapier - If you're considering alternatives
- Workflow automation services - Professional help
Summary
Self-hosted n8n setup involves:
- Server with Docker
- Docker Compose configuration
- SSL via Caddy reverse proxy
- Backup automation
- Monitoring setup
- Regular updates
Total setup time: 30-60 minutes for a production-ready deployment.
The ongoing maintenance is minimal - occasional updates and monitoring. The cost savings compared to per-execution pricing make self-hosting worthwhile for any serious automation use.
Need help with n8n setup or building complex workflows? Check out my n8n automation services or let's talk about your automation needs.