n8n Cloud is convenient. But self-hosting gives you control, privacy, and potentially significant cost savings.
Running n8n yourself isn't complicated — but doing it well requires knowing what matters.
Here's the complete guide to self-hosting n8n for production use.
Why Self-Host?
Reasons to self-host:
- Data privacy — Your data stays on your infrastructure
- Cost control — Predictable costs, especially at scale
- Customization — Modify n8n, add custom nodes
- No execution limits — Run as many workflows as your hardware allows
- Compliance — Meet regulatory requirements for data handling
Reasons to use Cloud:
- No infrastructure management
- Automatic updates and backups
- Built-in scaling
- Faster setup
For most individuals and small teams, Cloud makes sense. For organizations with specific requirements, self-hosting is worth the effort.
Basic Docker Setup
The fastest way to get n8n running:
```bash
docker run -it --rm \
--name n8n \
-p 5678:5678 \
-v n8n_data:/home/node/.n8n \
docker.n8n.io/n8nio/n8n
```
That's it. Open localhost:5678.
But this isn't production-ready. Let's fix that.
Production Docker Compose Setup
Create a docker-compose.yml:
```yaml
version: '3.8'
services:
n8n:
image: docker.n8n.io/n8nio/n8n
restart: always
ports:
- "5678:5678"
environment:
- N8N_HOST=your-domain.com
- N8N_PORT=5678
- N8N_PROTOCOL=https
- WEBHOOK_URL=https://your-domain.com/
- GENERIC_TIMEZONE=America/New_York
- N8N_SECURE_COOKIE=true
- N8N_ENCRYPTION_KEY=your-random-encryption-key
- 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
postgres:
image: postgres:15
restart: always
environment:
- POSTGRES_USER=n8n
- POSTGRES_PASSWORD=your-db-password
- POSTGRES_DB=n8n
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
n8n_data:
postgres_data:
```
Why PostgreSQL?
By default, n8n uses SQLite. This works but has limitations:
- Doesn't handle concurrent writes well
- Harder to back up while running
- Not suitable for high-volume production
PostgreSQL is the recommended production database.
Key Environment Variables
```
N8N_ENCRYPTION_KEY
```
Critical. Encrypts your credentials. Generate a random 32+ character string and keep it safe. If you lose this, you lose access to all stored credentials.
```
WEBHOOK_URL
```
Your public URL for webhooks. Must match your actual domain.
```
N8N_SECURE_COOKIE=true
```
Requires HTTPS. Enable this in production.
Reverse Proxy with Nginx
Don't expose n8n directly. Use a reverse proxy.
```nginx
server {
listen 80;
server_name your-domain.com;
return 301 https://\$server_name\$request_uri;
}
server {
listen 443 ssl http2;
server_name your-domain.com;
ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
location / {
proxy_pass http://localhost:5678;
proxy_http_version 1.1;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection "upgrade";
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;
# Important for webhooks
proxy_buffering off;
proxy_cache off;
chunked_transfer_encoding on;
}
}
```
Don't forget: The WebSocket upgrade headers are essential for n8n's UI to work properly.
Security Hardening
1. Enable Authentication
n8n 1.0+ includes built-in user management. On first launch, you'll create an owner account with email and password. This is enabled by default.
For additional security, you can:
- Require email verification for new users
- Set up SSO/SAML for enterprise (paid feature)
- Use environment variables to pre-configure the owner account:
```
N8N_USER_MANAGEMENT_JWT_SECRET=your-random-secret-string
```
Note: The old basic auth variables (N8N_BASIC_AUTH_*) were deprecated in n8n 1.0.
2. Disable Public API (If Not Needed)
```
N8N_PUBLIC_API_DISABLED=true
```
3. Restrict Webhook Access
Consider IP whitelisting for webhook endpoints if you know which services will call them.
4. Secure the Database
- Use strong passwords
- Don't expose PostgreSQL port publicly
- Enable SSL for database connections if over network
5. Keep Updated
Subscribe to n8n's security announcements. Update regularly.
```bash
docker-compose pull
docker-compose up -d
```
6. Network Isolation
Run n8n in its own network:
```yaml
networks:
n8n_network:
driver: bridge
```
Only expose what's necessary.
Backup Strategy
Database Backups
For PostgreSQL:
```bash
docker exec n8n-postgres pg_dump -U n8n n8n > backup-$(date +%Y%m%d).sql
```
Schedule this daily via cron.
Volume Backups
The n8n data volume contains:
- Workflow files (if using filesystem)
- Custom node configurations
- Local settings
Back up the Docker volume:
```bash
docker run --rm \
-v n8n_data:/source:ro \
-v /backups:/backup \
alpine tar czf /backup/n8n-data-$(date +%Y%m%d).tar.gz -C /source .
```
Backup the Encryption Key
If you lose N8N_ENCRYPTION_KEY, you lose all credentials. Store it securely:
- Password manager
- Encrypted secrets file
- Hardware security module (for enterprises)
Test Your Backups
A backup you haven't tested is not a backup. Periodically restore to a test environment.
Monitoring
Basic Health Check
Add to docker-compose:
```yaml
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:5678/healthz"]
interval: 30s
timeout: 10s
retries: 3
```
Execution Monitoring
n8n stores execution history. Query it:
- Set up alerts for failed executions
- Monitor execution duration trends
- Track active workflow count
External Monitoring
Use tools like:
- Uptime Kuma (self-hosted)
- Better Uptime
- Datadog / New Relic
Monitor both the n8n endpoint and critical webhook URLs.
Log Management
Docker logs fill up fast. Configure log rotation:
```yaml
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
```
Or ship logs to a centralized system (Loki, ELK, etc.).
Scaling Considerations
Vertical Scaling
n8n is single-threaded per workflow execution. For more throughput:
- More CPU cores help with concurrent workflows
- More RAM for large data transformations
- Fast SSD for database performance
Horizontal Scaling (Queue Mode)
For high-volume production, n8n supports queue mode with Redis:
```
EXECUTIONS_MODE=queue
QUEUE_BULL_REDIS_HOST=redis
QUEUE_BULL_REDIS_PORT=6379
```
This separates:
- Main process — Handles UI, webhook reception
- Worker processes — Execute workflows
You can run multiple workers for parallel execution.
When to Scale
Signs you need more resources:
- Webhook responses timing out
- Execution queue backing up
- UI becoming slow
- Database CPU maxed out
Upgrading n8n
Minor Updates
Usually safe. Pull and restart:
```bash
docker-compose pull
docker-compose up -d
```
Major Updates
Check the changelog for breaking changes. Test first:
- Back up everything
- Create test environment
- Test critical workflows
- Update production
Rollback Plan
Keep the previous image available:
```bash
docker tag docker.n8n.io/n8nio/n8n:latest docker.n8n.io/n8nio/n8n:backup
```
If something breaks, revert:
```bash
docker-compose down
# Update docker-compose.yml to use :backup tag
docker-compose up -d
```
Common Self-Hosting Mistakes
Mistake 1: No Encryption Key Backup
Lost encryption key = lost credentials = rebuild every integration.
Fix: Back up the key immediately. Store it separately from the database backup.
Mistake 2: SQLite in Production
Works until it doesn't. You'll hit issues at scale.
Fix: Use PostgreSQL from the start. Migration is painful later.
Mistake 3: No HTTPS
Credentials sent over HTTP are visible to anyone watching.
Fix: Always use HTTPS. Let's Encrypt is free.
Mistake 4: Exposed Database
PostgreSQL port open to the internet is an invitation for attacks.
Fix: Keep database internal to Docker network.
Mistake 5: No Monitoring
You don't know workflows are failing until users complain.
Fix: Set up Error Trigger workflow + external uptime monitoring.
Self-Hosting Checklist
Before going to production:
- [ ] PostgreSQL database (not SQLite)
- [ ] HTTPS enabled
- [ ] Authentication configured
- [ ] Encryption key backed up securely
- [ ] Reverse proxy configured
- [ ] Automated backups scheduled
- [ ] Backup restore tested
- [ ] Monitoring in place
- [ ] Error notification workflow active
- [ ] Resource limits set (memory, CPU)
- [ ] Log rotation configured
- [ ] Update process documented
Ready to master n8n deployments? Nodox.ai challenges include infrastructure scenarios where you build production-ready automations. Learn by doing, not just reading documentation.