Intermediate N8n Tutorial 3 min read

n8n Self-Hosting: Production Deployment Guide

#n8n #self-hosting #docker #production #postgresql #deployment

Why Self-Host n8n?

n8n Cloud is convenient, but self-hosting gives you:

  • No execution limits — run unlimited workflows on your own hardware
  • Data privacy — credentials and workflow data never leave your server
  • Cost control — a $6/month VPS handles most small-to-medium workloads
  • Full customization — custom nodes, environment variables, filesystem access

This guide sets up a production-grade n8n instance with Docker Compose, PostgreSQL, and an Nginx reverse proxy.

Prerequisites

  • A VPS or server running Ubuntu 22.04+ (4GB RAM minimum)
  • Docker and Docker Compose installed
  • A domain name pointing to your server’s IP

Step 1: Server Setup

# Update system
sudo apt update && sudo apt upgrade -y

# Install Docker
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER

# Install Docker Compose
sudo apt install docker-compose-plugin -y

# Verify
docker --version
docker compose version

Step 2: Directory Structure

mkdir -p ~/n8n/{data,postgres,files}
cd ~/n8n

Step 3: Docker Compose Configuration

Create ~/n8n/docker-compose.yml:

version: "3.8"

services:
  postgres:
    image: postgres:15
    restart: always
    environment:
      POSTGRES_DB: n8n
      POSTGRES_USER: n8n
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - ./postgres:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U n8n"]
      interval: 10s
      timeout: 5s
      retries: 5

  n8n:
    image: n8nio/n8n:latest
    restart: always
    ports:
      - "5678:5678"
    environment:
      # Database
      DB_TYPE: postgresdb
      DB_POSTGRESDB_HOST: postgres
      DB_POSTGRESDB_PORT: 5432
      DB_POSTGRESDB_DATABASE: n8n
      DB_POSTGRESDB_USER: n8n
      DB_POSTGRESDB_PASSWORD: ${POSTGRES_PASSWORD}

      # General
      N8N_HOST: ${N8N_HOST}
      N8N_PORT: 5678
      N8N_PROTOCOL: https
      WEBHOOK_URL: https://${N8N_HOST}/

      # Security
      N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}

      # Optional: basic auth
      # N8N_BASIC_AUTH_ACTIVE: "true"
      # N8N_BASIC_AUTH_USER: admin
      # N8N_BASIC_AUTH_PASSWORD: ${N8N_BASIC_AUTH_PASSWORD}

      # Timezone
      GENERIC_TIMEZONE: America/New_York

      # Execution settings
      EXECUTIONS_DATA_PRUNE: "true"
      EXECUTIONS_DATA_MAX_AGE: 336  # keep 14 days of execution history

    volumes:
      - ./data:/home/node/.n8n
      - ./files:/files  # for Read/Write File nodes
    depends_on:
      postgres:
        condition: service_healthy

Step 4: Environment Variables

Create ~/n8n/.env:

# Generate a strong password
POSTGRES_PASSWORD=$(openssl rand -base64 32)
echo "POSTGRES_PASSWORD=${POSTGRES_PASSWORD}"

# Generate encryption key (must be consistent — never change after first run)
N8N_ENCRYPTION_KEY=$(openssl rand -base64 32)
echo "N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}"

Edit ~/n8n/.env:

POSTGRES_PASSWORD=your-generated-password-here
N8N_ENCRYPTION_KEY=your-generated-key-here
N8N_HOST=n8n.yourdomain.com

Critical: Back up N8N_ENCRYPTION_KEY. If lost, all stored credentials are unrecoverable.

Step 5: Start n8n

cd ~/n8n
docker compose up -d

# Check logs
docker compose logs -f n8n

# Verify containers are running
docker compose ps

Step 6: Nginx Reverse Proxy with SSL

Install Nginx and Certbot:

sudo apt install nginx certbot python3-certbot-nginx -y

Create /etc/nginx/sites-available/n8n:

server {
    listen 80;
    server_name n8n.yourdomain.com;

    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;
        proxy_cache_bypass $http_upgrade;
        proxy_read_timeout 300s;
        proxy_connect_timeout 300s;
        proxy_send_timeout 300s;
    }
}

Enable and get SSL certificate:

sudo ln -s /etc/nginx/sites-available/n8n /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

# Get free SSL certificate
sudo certbot --nginx -d n8n.yourdomain.com

Certbot auto-configures HTTPS and sets up automatic renewal.

Step 7: Enable User Authentication

For production, always enable authentication. Add to .env:

N8N_BASIC_AUTH_ACTIVE=true
N8N_BASIC_AUTH_USER=admin
N8N_BASIC_AUTH_PASSWORD=your-secure-password

Or use n8n’s built-in User Management (recommended for teams):

  • After first login, go to Settings → Users
  • Create accounts with role-based access (owner / admin / member)

Updates and Maintenance

Update n8n to latest version:

cd ~/n8n
docker compose pull n8n
docker compose up -d n8n

Backup the database:

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

# Restore from backup
docker compose exec -T postgres psql -U n8n n8n < backup-20260408.sql

Monitor disk usage (execution history grows fast):

docker system df
du -sh ~/n8n/postgres/

The EXECUTIONS_DATA_MAX_AGE: 336 setting (14 days) in your compose file automatically prunes old execution history.

Performance Tuning

For high-throughput installations:

Increase workers:

# docker-compose.yml
n8n:
  environment:
    EXECUTIONS_MODE: queue
    QUEUE_BULL_REDIS_HOST: redis
    N8N_CONCURRENCY_PRODUCTION_LIMIT: 20

redis:
  image: redis:7
  restart: always

Queue mode with Redis enables horizontal scaling — run multiple n8n worker containers processing jobs from a shared queue.

PostgreSQL connection pool:

DB_POSTGRESDB_CONNECTION_LIMIT: 10

Monitoring

Check n8n health endpoint:

curl https://n8n.yourdomain.com/healthz
# → {"status":"ok"}

Set up uptime monitoring with UptimeRobot (free) or your preferred tool — monitor /healthz every 5 minutes.

View execution stats:

  • n8n UI → Settings → Execution History — see all past runs
  • Filter by failed executions to catch silent errors

Frequently Asked Questions

Can I migrate from n8n Cloud to self-hosted?

Yes. Export all workflows from n8n Cloud (Settings → Export Workflows), download credentials, then import to your self-hosted instance. Re-enter credentials (they are encrypted and can’t be exported directly).

How much server resources do I need?

  • Light use (< 100 executions/day): 1 vCPU, 1GB RAM
  • Medium use (100–1,000/day): 2 vCPU, 2GB RAM
  • Heavy use (1,000+/day): 4+ vCPU, 4GB RAM, Redis queue mode

A $6–12/month VPS (Hetzner, DigitalOcean, Hostinger) handles most use cases.

What happens if n8n crashes?

restart: always in Docker Compose ensures n8n restarts automatically. Combine with a process monitor like systemd:

sudo systemctl enable docker

Docker containers restart on system reboot too.

How do I run n8n workflows from the command line?

# Trigger a workflow via n8n CLI
docker compose exec n8n n8n execute --id WORKFLOW_ID

Or via webhook using curl — every active webhook workflow has a URL you can call programmatically.

Is self-hosted n8n free?

Yes — n8n is source-available under the Sustainable Use License. Self-hosting is free for personal and business use (commercial restrictions apply for building n8n-based products for resale).

Next Steps

Related Articles