Introduction
n8n ("n-eight-n"):
- Visual editor (drag & drop) for workflows
- 400+ ready nodes (Gmail, Slack, GitHub, Stripe, Notion, PostgreSQL...)
- Custom code in JavaScript / Python
- Incoming and outgoing webhooks
- Schedules (cron)
- AI nodes (OpenAI, Anthropic, etc.)
- Multi-tenant (Workflows + Credentials)
- Self-hosted (free) or cloud
Use cases: CRM sync, Slack alerts, light ETL, marketing automation, scraping, email processing.
Prerequisites
- Linux VPS 2 vCPU, 2 GB RAM
- Docker + Docker Compose
- Domain
- Root access
Step 1: Structure
sudo mkdir -p /opt/n8n
cd /opt/n8n
Step 2: docker-compose.yml
services:
n8n:
image: docker.n8n.io/n8nio/n8n:latest
restart: unless-stopped
environment:
- N8N_HOST=n8n.your-domain.com
- N8N_PORT=5678
- N8N_PROTOCOL=https
- NODE_ENV=production
- WEBHOOK_URL=https://n8n.your-domain.com/
- GENERIC_TIMEZONE=Europe/Paris
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=postgres
- DB_POSTGRESDB_DATABASE=n8n
- DB_POSTGRESDB_USER=n8n
- DB_POSTGRESDB_PASSWORD=strong-secret
- N8N_ENCRYPTION_KEY=random-32-char-key
volumes:
- n8n_data:/home/node/.n8n
- ./files:/files
depends_on:
- postgres
ports:
- "127.0.0.1:5678:5678"
postgres:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_USER: n8n
POSTGRES_PASSWORD: strong-secret
POSTGRES_DB: n8n
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
n8n_data:
postgres_data:
openssl rand -hex 16
Step 3: Start
sudo docker compose up -d
sudo docker compose logs -f
Step 4: Nginx reverse proxy
server {
listen 443 ssl http2;
server_name n8n.your-domain.com;
location / {
proxy_pass http://127.0.0.1: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;
proxy_read_timeout 86400;
}
}
sudo certbot --nginx -d n8n.your-domain.com
Step 5: First access
Visit https://n8n.your-domain.com. Create the owner account.
Step 6: First workflow
Workflows > New > Add first step.
Example: monitor a GitHub repo and post to Slack on new issue.
- Trigger node:
GitHub Trigger> eventissues> authenticate with Personal Access Token - Action node:
Slack> OAuth or webhook URL - Message:
New issue in {{$json.repository.name}}: {{$json.issue.title}}
Click Execute Workflow to test, then Active for prod.
Step 7: Webhook trigger
- Add a
Webhooknode - Note generated URL (production)
- Method: POST
- Active
Test:
curl -X POST https://n8n.your-domain.com/webhook/abc123 \
-H "Content-Type: application/json" \
-d '{"name":"test","value":42}'
Step 8: Schedule trigger
Hourly:
Schedule Triggernode- Rule:
Hours - Hours Between Triggers: 1
Cron mode: 0 9 * * MON-FRI.
Step 9: Custom code
Code node:
const items = $input.all();
const result = items.map(item => ({
json: {
upper: item.json.name.toUpperCase(),
timestamp: new Date().toISOString()
}
}));
return result;
Access previous nodes: $('NodeName').first().json.field.
Step 10: AI nodes
- Add
OpenAIorAnthropicnode - Configure API key
- Choose model (gpt-4, claude-3-5-sonnet...)
- Build prompt:
{{$json.email_body}}
Use cases: auto email summary, classification, response generation.
Step 11: Secure credentials
n8n encrypts credentials with N8N_ENCRYPTION_KEY.
Settings > Credentials. Auth types: API Key, OAuth2, Basic Auth, HTTP Bearer, SSH Private Key.
⚠️ Backup the encryption key. Without it, credentials in a backup are unrecoverable.
Step 12: Backup
sudo docker compose exec postgres pg_dump -U n8n n8n | gzip > n8n-db-$(date +%F).sql.gz
sudo docker run --rm -v opt-n8n_n8n_data:/data -v $PWD:/backup busybox tar czf /backup/n8n-data-$(date +%F).tar.gz /data
⚠️ Also backup docker-compose.yml and note N8N_ENCRYPTION_KEY.
Step 13: Update
cd /opt/n8n
sudo docker compose pull
sudo docker compose up -d
n8n auto-runs DB migrations.
Troubleshooting
Workflow doesn't trigger
- Check Active state
- Webhook: use
ProductionURL (notTest) - Cron: check timezone (
GENERIC_TIMEZONE)
"Encryption key changed"
You lost the encryption key. Re-create credentials manually.
OOM kill
Increase RAM:
deploy:
resources:
limits:
memory: 2G
Webhook timeout via Cloudflare
Increase Cloudflare timeout or use direct webhook URL.
"Cannot connect to database"
docker compose logs postgres
Useful commands
sudo docker compose logs -f n8n
sudo docker compose restart n8n
curl -X GET https://n8n.your-domain.com/api/v1/workflows \
-H "X-N8N-API-KEY: YOUR_KEY"
curl -X POST https://n8n.your-domain.com/api/v1/workflows/123/activate \
-H "X-N8N-API-KEY: YOUR_KEY"
n8n export:workflow --all --output=workflows.json
n8n import:workflow --input=workflows.json
Conclusion
n8n provides:
- No-code automation (or light JS)
- 400+ integrations
- Robust webhooks and schedules
- AI nodes for smart automation
- Self-hosted = total data control
Going further:
- Pair with Bookstack to document workflows
- Enable Queue mode (Redis) for scaling
- For critical prod, consider n8n Cloud
Resources
- Official docs: https://docs.n8n.io
- Workflow templates: https://n8n.io/workflows
- Community: https://community.n8n.io
- Source: https://github.com/n8n-io/n8n

















