Skip to main content
Back to Category

n8n Setup: Self-Hosted Workflow Automation

n8n Docker installation, webhook integrations, workflow creation, 400+ app connections, scheduled tasks, credentials management and production deployment.

Read time: 15 min Self-Hosting
n8nautomationworkflowself-hostingdockerwebhookintegration
Author
REXE Teknoloji Network & Security Team
Editor
REXE Teknoloji Technical Editorial
First published
Last updated

n8n Setup: Self-Hosted Workflow Automation

n8n is an open-source workflow automation platform with a visual interface that can connect 400+ applications and services. You can run it on your own server as a self-hosted alternative to services like Zapier and Make (Integromat). You can create complex automations without writing code, or add custom logic with JavaScript/Python.

What is n8n?

n8n (short for "nodemation") lets you build workflows with node-based visual programming. Key features:

  • 400+ Integrations: Slack, GitHub, Google Sheets, Notion, Airtable and more
  • Webhook Support: Use HTTP requests as triggers
  • Scheduled Tasks: Cron-based scheduling
  • Code Support: JavaScript and Python nodes
  • Error Handling: Retry mechanism and error flows
  • Encrypted Credentials: API keys stored securely

System Requirements

  • Server with Docker and Docker Compose installed
  • Minimum 1 GB RAM (2 GB recommended)
  • PostgreSQL (recommended for production) or SQLite

Basic Docker Installation

Quick Start with SQLite

hljs yaml
# docker-compose.yml
version: '3.8'

services:
  n8n:
    image: n8nio/n8n:latest
    container_name: n8n
    restart: unless-stopped
    environment:
      - N8N_HOST=n8n.example.com
      - N8N_PORT=5678
      - N8N_PROTOCOL=https
      - NODE_ENV=production
      - WEBHOOK_URL=https://n8n.example.com/
      - GENERIC_TIMEZONE=Europe/London
      - N8N_ENCRYPTION_KEY=strong-encryption-key
    volumes:
      - ./n8n-data:/home/node/.n8n
    ports:
      - "127.0.0.1:5678:5678"
hljs bash
# Start the container
docker compose up -d

# Check logs
docker logs n8n -f

N8N_ENCRYPTION_KEY is used to encrypt credentials. If you lose this value, all your credentials become inaccessible. Store it in a safe place.

Production Setup with PostgreSQL

hljs yaml
version: '3.8'

services:
  postgres:
    image: postgres:15
    container_name: n8n-postgres
    restart: unless-stopped
    environment:
      POSTGRES_DB: n8n
      POSTGRES_USER: n8n
      POSTGRES_PASSWORD: strong-password
    volumes:
      - postgres-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U n8n"]
      interval: 5s
      timeout: 5s
      retries: 10

  n8n:
    image: n8nio/n8n:latest
    container_name: n8n
    restart: unless-stopped
    depends_on:
      postgres:
        condition: service_healthy
    environment:
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_HOST=postgres
      - DB_POSTGRESDB_PORT=5432
      - DB_POSTGRESDB_DATABASE=n8n
      - DB_POSTGRESDB_USER=n8n
      - DB_POSTGRESDB_PASSWORD=strong-password
      - N8N_HOST=n8n.example.com
      - N8N_PROTOCOL=https
      - WEBHOOK_URL=https://n8n.example.com/
      - GENERIC_TIMEZONE=Europe/London
      - N8N_ENCRYPTION_KEY=strong-encryption-key
      - N8N_BASIC_AUTH_ACTIVE=true
      - N8N_BASIC_AUTH_USER=admin
      - N8N_BASIC_AUTH_PASSWORD=admin-password
    volumes:
      - ./n8n-data:/home/node/.n8n
    ports:
      - "127.0.0.1:5678:5678"

volumes:
  postgres-data:

Nginx Reverse Proxy

hljs nginx
server {
    listen 80;
    server_name n8n.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name n8n.example.com;

    ssl_certificate /etc/letsencrypt/live/n8n.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/n8n.example.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:5678;
        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;

        # WebSocket support (required for n8n)
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_read_timeout 3600;
    }
}

Creating Basic Workflows

First Workflow: Webhook → Slack Notification

  1. Click New Workflow
  2. Add node with + → select Webhook
    • HTTP Method: POST
    • Path: /slack-notify
  3. Add new node with + → select Slack
    • Operation: Send Message
    • Channel: #general
    • Message: {{ $json.message }}
  4. Save and Activate
hljs bash
# Test the webhook
curl -X POST https://n8n.example.com/webhook/slack-notify \
  -H "Content-Type: application/json" \
  -d '{"message": "Hello n8n!"}'

Trigger Types

Webhook Trigger

hljs javascript
// Webhook node settings
{
  "httpMethod": "POST",
  "path": "my-webhook",
  "responseMode": "onReceived",
  "responseData": "allEntries"
}

Cron (Schedule) Trigger

# Cron expressions
0 9 * * 1-5    # Weekdays at 09:00
*/15 * * * *   # Every 15 minutes
0 0 * * *      # Every midnight
0 8 * * 1      # Every Monday at 08:00

Credentials Management

Settings → Credentials → Add Credential

Example: GitHub API
- Credential Type: GitHub API
- Access Token: ghp_xxxxxxxxxxxx
- Test the connection

GitHub → Slack Notification

GitHub Trigger (push event)
  → IF (branch == 'main')
    → Slack ("New deploy: {{ $json.commits[0].message }}")
    → Email (notify team)

Daily Report

Cron Trigger (every morning at 09:00)
  → PostgreSQL (fetch yesterday's sales)
  → Code (format data)
  → Google Sheets (add to report)
  → Slack (send summary)

Form → CRM Integration

Webhook (form submit)
  → Validate (required fields)
  → HubSpot (create contact)
  → Email (welcome email)
  → Slack (notify sales team)

Queue Mode (High Load)

Use queue mode for high workloads in production:

hljs yaml
environment:
  - EXECUTIONS_MODE=queue
  - QUEUE_BULL_REDIS_HOST=redis
  - QUEUE_BULL_REDIS_PORT=6379

# Add Redis service
redis:
  image: redis:7-alpine
  container_name: n8n-redis
  restart: unless-stopped

Backup

hljs bash
# Backup n8n data
tar -czf n8n-backup-$(date +%Y%m%d).tar.gz ./n8n-data/

# PostgreSQL backup
docker exec n8n-postgres pg_dump -U n8n n8n > n8n-db-$(date +%Y%m%d).sql

# Automated backup
cat > /etc/cron.daily/n8n-backup << 'EOF'
#!/bin/bash
docker exec n8n-postgres pg_dump -U n8n n8n | \
  gzip > /backups/n8n-$(date +%Y%m%d).sql.gz
find /backups -name "n8n-*.sql.gz" -mtime +30 -delete
EOF

With n8n on REXE VPS servers, you can automate all your business processes. With 2 GB RAM you can run hundreds of workflows.

Frequently Asked Questions

What is the difference between n8n and Zapier?

n8n is self-hosted and open-source; Zapier is cloud-based and paid. With n8n, your data stays on your own server and you can create unlimited workflows and executions. Zapier may be more user-friendly but has monthly execution limits and high costs. n8n also allows you to write custom code with JavaScript/Python.

My webhook URL isn't working, can't be accessed from outside.

Make sure the WEBHOOK_URL environment variable is correctly set (https://n8n.example.com/). Check that the Nginx proxy supports WebSocket connections (Upgrade and Connection headers). Verify that port 443 is open in the firewall. Make sure the workflow is in 'Active' state in n8n.

I lost my credentials, forgot the encryption key.

If N8N_ENCRYPTION_KEY is changed, existing credentials cannot be decrypted. In this case, you need to recreate all credentials. This is why storing the encryption key in a safe place (password manager, vault) is critical. Back up this key when making backups.

n8n is using too much memory, how do I optimize it?

Limit execution history: EXECUTIONS_DATA_MAX_AGE=168 (7 days). For large datasets, save binary data to the filesystem: N8N_DEFAULT_BINARY_DATA_MODE=filesystem. Control worker count using queue mode. Disable unnecessary workflows.

How do I debug in n8n?

You can see the output of each node in the workflow editor. Test individual nodes with 'Execute Node'. Review past runs from the execution list. Add an error node to catch errors and receive Slack/email notifications. Check system logs with docker logs n8n.

Is it safe to update n8n, will I lose my data?

If using PostgreSQL, updating is safe. Take a database backup before updating: docker exec n8n-postgres pg_dump -U n8n n8n > backup.sql. Then update with docker compose pull && docker compose up -d. n8n performs automatic migrations. If using SQLite, back up the ./n8n-data/ directory.

Related Articles

Network TrafficInbound GbpsOutbound Gbps