Logo

n8n: self-hosted workflow automation

n8n: self-hosted workflow automation

n8n is an open-source visual automation tool, Zapier/Make-style. 400+ integrations, code execution, webhooks. Connect your APIs and automate repetitive tasks without code or with light JS.

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.

  1. Trigger node: GitHub Trigger > event issues > authenticate with Personal Access Token
  2. Action node: Slack > OAuth or webhook URL
  3. Message: New issue in {{$json.repository.name}}: {{$json.issue.title}}

Click Execute Workflow to test, then Active for prod.

Step 7: Webhook trigger

  1. Add a Webhook node
  2. Note generated URL (production)
  3. Method: POST
  4. 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:

  1. Schedule Trigger node
  2. Rule: Hours
  3. 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

  1. Add OpenAI or Anthropic node
  2. Configure API key
  3. Choose model (gpt-4, claude-3-5-sonnet...)
  4. 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 Production URL (not Test)
  • 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

Join our Discord community server

For any questions, suggestions, or just to chat with the community, join us on Discord!

900+Members