Self-Hosting n8n: Workflow Automation 2026
n8n is the open source Zapier alternative with 400+ integrations and a visual workflow builder. Self-hosting gives you unlimited workflows, no execution limits, and full control over your automation data.
Why Self-Host n8n
Zapier's pricing is consumption-based and can scale uncomfortably fast. The Starter plan at $19.99/month gives 750 tasks. The Professional plan at $49/month covers 2,000 tasks. For anyone running serious automations — syncing CRM data, processing webhooks, orchestrating marketing workflows — task limits become a constraint within months. Make (formerly Integromat) follows a similar operations-based model.
Self-hosting n8n costs the price of a VPS — a €4.50/month Hetzner server handles dozens of concurrent workflows with no task caps. Annual cost: approximately $54 versus Zapier's $240-$600. For data-intensive automation pipelines running thousands of executions per month, self-hosting saves $2,000+ per year.
Data privacy is the other major driver. Automation workflows often touch sensitive data: customer records from your CRM, payment notifications, user-generated content. When you run Zapier or Make, that data passes through their cloud infrastructure. Self-hosted n8n keeps every piece of data — every webhook payload, every API response — on your own server.
No execution caps, no step limits. n8n Cloud's community plan limits workflows to a maximum of 5 steps and 5 active workflows. Self-hosted n8n has no such restrictions. You can build arbitrarily complex workflows with as many nodes and parallel branches as your server can handle.
400+ integrations and custom nodes: n8n's node library covers every major SaaS product, and you can write custom JavaScript inside the Code node for anything not covered. Unlike no-code tools with locked-down logic, n8n lets you run arbitrary code within your workflows.
When NOT to self-host n8n: If your team is non-technical and needs a tool that IT doesn't have to maintain, Zapier's polished UX and reliable managed infrastructure are worth the cost. Also, n8n's encryption key must be backed up carefully — if you lose it, all stored credentials become unreadable. For teams that can't maintain that operational discipline, a managed service is safer.
Prerequisites
n8n is lighter than most tools in this guide — the minimum requirements are genuinely achievable on budget hardware. Still, choosing the right VPS provider for self-hosting affects your webhook response times and workflow execution reliability.
Server specs: 1 GB RAM works for development and light automation. For production with concurrent workflows, 2 GB RAM gives comfortable headroom. CPU matters for workflows that process large datasets or run expensive JavaScript in Code nodes. A 2 vCPU server handles most workloads without bottlenecking.
PostgreSQL vs SQLite: n8n defaults to SQLite for simplicity, but SQLite is not recommended for production. Concurrent workflow executions can cause SQLite write contention, leading to failed executions. The Docker Compose setup here uses PostgreSQL, which handles concurrent writes cleanly and scales to thousands of workflow executions per day.
Encryption key backup: Generate your N8N_ENCRYPTION_KEY with openssl rand -hex 32 and store it in a secure password manager immediately. This key encrypts all stored credentials (API keys, passwords, tokens). If you lose it — for example, by accidentally deleting the Docker volume — every integration credential becomes permanently unreadable and must be re-entered manually.
Operating system: Ubuntu 22.04 LTS. n8n's Docker image is tested on Ubuntu, and the webhook URL routing via Caddy follows standard patterns well-documented in the community.
SMTP for workflow notifications: Many n8n workflows send email notifications. Configure SMTP early so the Email node works without special attention when building workflows later.
Skills required: Basic Docker Compose familiarity and understanding of environment variables. Building workflows in n8n itself requires no coding, though JavaScript knowledge unlocks the full power of the Code node.
Requirements
- VPS with 1 GB RAM minimum (2 GB recommended)
- Docker and Docker Compose
- Domain name (e.g.,
n8n.yourdomain.com) - 10+ GB disk
Step 1: Create Docker Compose
# docker-compose.yml
services:
n8n:
image: n8nio/n8n:latest
container_name: n8n
restart: unless-stopped
ports:
- "5678:5678"
volumes:
- n8n_data:/home/node/.n8n
environment:
- N8N_HOST=n8n.yourdomain.com
- N8N_PORT=5678
- N8N_PROTOCOL=https
- WEBHOOK_URL=https://n8n.yourdomain.com/
- N8N_ENCRYPTION_KEY=your-random-encryption-key
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=db
- DB_POSTGRESDB_PORT=5432
- DB_POSTGRESDB_DATABASE=n8n
- DB_POSTGRESDB_USER=n8n
- DB_POSTGRESDB_PASSWORD=your-strong-password
- GENERIC_TIMEZONE=America/New_York
depends_on:
- db
db:
image: postgres:16-alpine
container_name: n8n-db
restart: unless-stopped
volumes:
- db_data:/var/lib/postgresql/data
environment:
- POSTGRES_DB=n8n
- POSTGRES_USER=n8n
- POSTGRES_PASSWORD=your-strong-password
volumes:
n8n_data:
db_data:
Step 2: Generate Encryption Key
# Generate a random encryption key (keep this safe!)
openssl rand -hex 32
Replace your-random-encryption-key in the compose file. This encrypts all stored credentials. If you lose this key, all saved credentials become unreadable.
Step 3: Start n8n
docker compose up -d
Step 4: Reverse Proxy (Caddy)
# /etc/caddy/Caddyfile
n8n.yourdomain.com {
reverse_proxy localhost:5678
}
sudo systemctl restart caddy
Step 5: Initial Setup
- Open
https://n8n.yourdomain.com - Create your admin account
- Set up your first workflow
Step 6: Essential Configuration
Environment variables to consider:
| Variable | Purpose | Example |
|---|---|---|
N8N_ENCRYPTION_KEY | Encrypts credentials | Random 64-char hex |
N8N_USER_MANAGEMENT_DISABLED | Single user mode | true |
EXECUTIONS_DATA_PRUNE | Auto-delete old executions | true |
EXECUTIONS_DATA_MAX_AGE | Execution retention | 168 (7 days) |
N8N_METRICS | Enable Prometheus metrics | true |
N8N_DIAGNOSTICS_ENABLED | Disable telemetry | false |
N8N_TEMPLATES_ENABLED | Show workflow templates | true |
Step 7: Set Up SMTP (For Email Nodes)
Add to your environment:
N8N_EMAIL_MODE=smtp
N8N_SMTP_HOST=smtp.resend.com
N8N_SMTP_PORT=587
N8N_SMTP_USER=resend
N8N_SMTP_PASS=re_your_api_key
N8N_SMTP_SENDER=n8n@yourdomain.com
N8N_SMTP_SSL=true
Step 8: Popular Workflow Examples
Slack notification on form submission:
- Webhook Trigger → receives form data
- Set node → format message
- Slack node → post to channel
Daily database backup to S3:
- Cron Trigger → runs daily
- Execute Command →
pg_dump - AWS S3 → upload backup file
GitHub PR → Linear ticket:
- GitHub Trigger → on PR opened
- Set node → map fields
- Linear → create issue
Production Hardening
Execution pruning (prevent disk filling up):
EXECUTIONS_DATA_PRUNE=true
EXECUTIONS_DATA_MAX_AGE=168
EXECUTIONS_DATA_PRUNE_MAX_COUNT=10000
Backups:
# Database backup (daily cron)
docker exec n8n-db pg_dump -U n8n n8n > /backups/n8n-$(date +%Y%m%d).sql
# Credentials and workflows
docker cp n8n:/home/node/.n8n /backups/n8n-data-$(date +%Y%m%d)
Pair your local backups with automated server backups using restic to push encrypted snapshots to offsite storage. The PostgreSQL database contains all your workflow definitions and execution history — it's the critical thing to protect.
Updates:
docker compose pull
docker compose up -d
Monitoring:
- Monitor port 5678 with Uptime Kuma
- Enable Prometheus metrics for workflow monitoring
- Set up alerts for failed executions
Resource Usage
| Workflows | RAM | CPU | Disk |
|---|---|---|---|
| 1-20 | 1 GB | 1 core | 10 GB |
| 20-100 | 2 GB | 2 cores | 20 GB |
| 100+ | 4 GB | 4 cores | 50 GB |
VPS Recommendations
| Provider | Spec | Price |
|---|---|---|
| Hetzner | 2 vCPU, 4 GB RAM | €4.50/month |
| DigitalOcean | 1 vCPU, 2 GB RAM | $12/month |
| Linode | 1 vCPU, 2 GB RAM | $12/month |
Production Security Hardening
n8n stores API credentials and runs code that touches external services — it's an attractive target. The webhook endpoint is public-facing by design, which makes hardening especially important. Follow the comprehensive self-hosting security checklist alongside these n8n-specific measures.
UFW firewall: Block direct access to n8n's port 5678 — all traffic should go through Caddy.
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw deny 5678/tcp # Block direct n8n access
sudo ufw enable
Fail2ban:
sudo apt install fail2ban -y
/etc/fail2ban/jail.local:
[sshd]
enabled = true
maxretry = 5
bantime = 3600
findtime = 600
Encryption key and secrets in .env: Never hardcode the encryption key in your Docker Compose file. Use a .env file:
# .env
N8N_ENCRYPTION_KEY=your-32-byte-hex-key
DB_POSTGRESDB_PASSWORD=your-strong-password
chmod 600 .env
echo ".env" >> .gitignore
Back up the encryption key separately from your server — store it in a password manager or secrets vault. The key is not stored in the database; it's read from the environment at startup. If the server is lost without the key, all credentials are gone permanently.
Disable SSH password auth: Edit /etc/ssh/sshd_config:
PasswordAuthentication no
PermitRootLogin no
Restart: sudo systemctl restart sshd
Automatic security updates:
sudo apt install unattended-upgrades -y
sudo dpkg-reconfigure --priority=low unattended-upgrades
n8n access controls: Enable n8n's built-in user management. Set N8N_USER_MANAGEMENT_DISABLED=false and create individual accounts for each team member rather than sharing a single login. This provides an audit trail of who created or modified which workflow.
Troubleshooting Common Issues
Webhooks work locally but not from external services
The WEBHOOK_URL environment variable must be the full public URL including the trailing slash: https://n8n.yourdomain.com/. If it's wrong, n8n generates incorrect webhook URLs when you create webhook triggers. Restart after fixing, then re-check the webhook URL shown in any Webhook node.
"Credentials not found" after container restart
If you changed the N8N_ENCRYPTION_KEY between restarts, credentials encrypted with the old key can't be decrypted. The key must remain constant for the lifetime of the n8n installation. Check that your .env file persists correctly and that the Docker volume containing /home/node/.n8n wasn't deleted. If credentials are truly lost, you'll need to re-enter them in n8n's credential manager.
PostgreSQL connection refused on startup
n8n starts before PostgreSQL is ready to accept connections. Add a healthcheck to the db service in your Docker Compose, or set N8N_SKIP_WEBHOOK_DEREGISTRATION_SHUTDOWN=true and let Docker's restart: unless-stopped handle recovery. Usually n8n's automatic retry handles this within 30 seconds — check docker logs n8n for "Connected to database" confirmation.
Disk fills up from execution logs
With EXECUTIONS_DATA_PRUNE disabled (the default), every workflow execution is stored forever in PostgreSQL. Enable pruning: EXECUTIONS_DATA_PRUNE=true and EXECUTIONS_DATA_MAX_AGE=168 (7 days in hours). To clean up existing data: go to n8n's Settings → Executions and bulk delete old executions, or run DELETE FROM execution_entity WHERE "startedAt" < NOW() - INTERVAL '7 days'; directly in PostgreSQL.
Email node fails with "Connection refused"
Verify your SMTP configuration by checking if port 587 is accessible: docker exec n8n nc -zv smtp.resend.com 587. Some VPS providers block outbound SMTP on port 25 and 587 by default (Hetzner requires a support request to unlock). Use port 465 (SSL) or Resend/Postmark's HTTP API as an alternative via n8n's HTTP Request node.
Ongoing Maintenance and Operations
n8n is one of the more pleasant self-hosted applications to maintain long-term. The operational surface is small — it's essentially one container plus a database — and the community is active with good troubleshooting resources.
Workflow organization. As your automation library grows, adopt a naming convention early. A good pattern: [Team/Project] - [What it does] - [Trigger type]. For example: Sales - New Lead → CRM + Slack - Webhook or DevOps - Deploy notify - Cron. Without consistent naming, finding the right workflow in a library of 50+ becomes time-consuming.
Error handling in workflows. Production workflows should handle errors gracefully. Add an Error Trigger node that catches failed executions and sends you a Slack or email notification with the workflow name and error message. Without this, failed workflows silently fail — you only discover the problem when someone notices something didn't happen. Go to n8n's Settings → Error Workflow to set a global error handler.
Credential management hygiene. n8n stores API credentials encrypted with your N8N_ENCRYPTION_KEY. These credentials should be treated like passwords — rotate them annually and immediately when team members with access leave. When rotating credentials, update them in n8n's Credentials panel and test affected workflows before considering the rotation complete.
Execution log review. n8n logs every workflow execution with inputs, outputs, and timing. These logs are invaluable for debugging, but reviewing them manually doesn't scale. Use n8n's built-in filtering to review failed executions weekly: go to Executions and filter by status "Error." Most recurring failures have patterns — fix them at the source rather than repeatedly restarting failed runs.
Scaling workflow complexity. When workflows get complex (20+ nodes, multiple branches), break them into smaller sub-workflows called via n8n's Execute Workflow node. This makes individual pieces testable, reusable, and easier to debug. A common pattern: a "Router" workflow that receives a webhook and dispatches to specialized sub-workflows based on the event type.
Upgrading n8n safely. n8n releases updates frequently, including security patches. Before upgrading, check the n8n changelog for breaking changes (especially credential format changes or removed node parameters). The upgrade procedure is: stop n8n, pull the new image, start it — the database migrations run automatically. Keep one previous version available by tagging your current image before pulling the new one: docker tag n8nio/n8n:current n8nio/n8n:backup.
Webhook reliability. If external services (GitHub, Stripe, Slack) report webhook delivery failures, the most common cause is your server being temporarily unreachable. n8n doesn't have built-in webhook queuing — if your server is down when a webhook fires, the event is lost. For critical automations, implement idempotent retry logic on the sending side or consider deploying a lightweight webhook receiver (like a simple Express server) that persists events to a queue even when n8n is down.
Compare automation platforms on OSSAlt — integrations, pricing, and self-hosting options side by side.
See open source alternatives to n8n on OSSAlt.