← Back to blog
    July 16, 202610 min read

    How to Self-Host n8n: Complete Production Setup Guide

    A step-by-step guide to deploying n8n in production with Docker, PostgreSQL, SSL, and security hardening — including cost comparisons with n8n Cloud and performance optimization tips for 2026.

    n8nself-hostingdockerautomationworkflow-automationdevops

    How to Self-Host n8n: Complete Production Setup Guide

    Self-hosting n8n gives you full control over your automation workflows, data residency, and costs — but a production deployment requires Docker, PostgreSQL, a reverse proxy with SSL, and proper security hardening. This guide walks through every step, from server provisioning to production-ready deployment, with current 2026 pricing and requirements.

    Whether you are migrating from n8n Cloud or starting fresh, this guide covers the infrastructure sizing, Docker Compose configuration, database setup, SSL termination, security hardening, and backup strategies you need for a reliable self-hosted n8n instance.

    What You Need Before You Start

    A production n8n deployment requires four core components: a Linux server, a container runtime, a database, and a public domain with DNS configured.

    System Requirements (2026)

    The minimum and recommended specifications have shifted upward in 2025-2026 as n8n has added AI-heavy features and improved its concurrency model:

    ResourceMinimum (Testing)Recommended (Production)AI-Heavy Workloads
    CPU2 vCPUs4 vCPUs8+ vCPUs
    RAM2 GB8 GB16+ GB
    Storage20 GB SSD80 GB NVMe SSD160+ GB NVMe
    DatabaseSQLitePostgreSQL 15+PostgreSQL 15+
    RuntimeDocker 24+ or Node.js 20.19+Docker 24+Docker 24+ + Redis 6+

    Node.js 20.19 is now the baseline for self-hosting n8n — earlier guides referenced Node.js 16+, but the 2025-2026 updates have raised this requirement. Docker Engine 24.0+ with Docker Compose v2 is the standard deployment method.

    Prerequisites Checklist

    • An Ubuntu 22.04 or 24.04 VPS from a provider like Hetzner, DigitalOcean, or AWS
    • A domain name (e.g., automation.yourcompany.com) with DNS A record pointing to your server IP
    • Docker Engine 24+ and Docker Compose v2 installed
    • SSH key access to your server (password authentication should be disabled)

    Step 1: Provision and Secure Your Server

    Before installing n8n, harden your server. A surprising number of self-hosting failures stem from neglected server-level security rather than n8n configuration issues.

    Basic Server Hardening

    # Update the system
    sudo apt update && sudo apt upgrade -y
    
    # Create a non-root user
    sudo adduser n8n
    sudo usermod -aG sudo n8n
    
    # Configure SSH key authentication and disable password login
    sudo nano /etc/ssh/sshd_config
    # Set: PasswordAuthentication no
    sudo systemctl restart sshd
    
    # Configure firewall
    sudo ufw default deny incoming
    sudo ufw default allow outgoing
    sudo ufw allow 22/tcp
    sudo ufw allow 80/tcp
    sudo ufw allow 443/tcp
    sudo ufw enable
    
    # Install Fail2Ban for brute-force protection
    sudo apt install fail2ban -y
    

    Only ports 22 (SSH), 80 (HTTP), and 443 (HTTPS) should be open. n8n runs on port 5678 internally but should never be exposed directly to the internet.

    Step 2: Create the Docker Compose Stack

    Create a directory structure and define your services. This setup uses PostgreSQL as the database — SQLite is fine for testing but causes concurrency and backup problems in production.

    Directory Structure

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

    docker-compose.yml

    version: "3.8"
    
    services:
      n8n:
        image: n8nio/n8n:1.65.0
        restart: unless-stopped
        environment:
          N8N_HOST: automation.example.com
          N8N_PORT: 5678
          N8N_PROTOCOL: https
          N8N_ENCRYPTION_KEY: "replace-with-a-32-char-random-string"
          DB_TYPE: postgres
          DB_POSTGRESDB_DATABASE: n8n
          DB_POSTGRESDB_HOST: postgres
          DB_POSTGRESDB_PORT: 5432
          DB_POSTGRESDB_USER: n8n
          DB_POSTGRESDB_PASSWORD: "replace-with-strong-db-password"
          N8N_SECURE_COOKIE: "true"
          N8N_DIAGNOSTICS_ENABLED: "false"
          EXECUTIONS_DATA_PRUNE: "true"
          EXECUTIONS_DATA_MAX_AGE: "168"
        ports:
          - "127.0.0.1:5678:5678"
        volumes:
          - ./data:/home/node/.n8n
          - ./files:/files
        depends_on:
          - postgres
    
      postgres:
        image: postgres:15-alpine
        restart: unless-stopped
        environment:
          POSTGRES_USER: n8n
          POSTGRES_PASSWORD: "replace-with-strong-db-password"
          POSTGRES_DB: n8n
        volumes:
          - ./postgres-data:/var/lib/postgresql/data
    

    Critical Configuration Choices

    Pin your image version. Using n8nio/n8n:latest is one of the most common pitfalls in self-hosting n8n. Unpinned images can introduce breaking changes on every pull. Always pin to a specific version like 1.65.0 and upgrade deliberately after testing on a staging environment.

    Use PostgreSQL, not SQLite. SQLite works for quick local tests but lacks the concurrency and reliability needed for production workflows. PostgreSQL 13-17 is the supported range, with version 15 being the most commonly recommended in 2026 guides. SQLite also complicates backups — you need to coordinate file copies carefully to avoid corruption, while PostgreSQL supports proper transactional backups.

    Bind to localhost only. Note the port binding 127.0.0.1:5678:5678 — this ensures n8n is only accessible via the reverse proxy, not directly. This is a security best practice that prevents direct access to the n8n port from the internet.

    Enable execution data pruning. The EXECUTIONS_DATA_PRUNE and EXECUTIONS_DATA_MAX_AGE settings automatically clean up execution logs older than 7 days (168 hours). Without this, your database will grow indefinitely and eventually degrade performance.

    Generate a Strong Encryption Key

    # Generate a random 32-character encryption key
    openssl rand -hex 16
    

    The N8N_ENCRYPTION_KEY encrypts stored credentials in your n8n database. If you lose this key, all stored credentials become unrecoverable. Store it securely — it is one of the most critical secrets in your deployment.

    Step 3: Start the Stack

    docker compose up -d
    docker compose ps
    docker compose logs -f n8n
    

    Wait 2-3 minutes for n8n to fully initialize. You should see log output indicating the server is running on port 5678. At this point, n8n is running but only accessible locally — the next step is to add a reverse proxy for public access with SSL.

    Step 4: Configure Nginx Reverse Proxy with SSL

    A reverse proxy handles HTTPS termination, redirects HTTP to HTTPS, and provides security headers. Caddy is simpler (automatic HTTPS), but Nginx offers more granular control.

    Install Nginx

    sudo apt install nginx -y
    

    Nginx Configuration

    server {
        listen 80;
        server_name automation.example.com;
        return 301 https://$server_name$request_uri;
    }
    
    server {
        listen 443 ssl http2;
        server_name automation.example.com;
    
        ssl_certificate /etc/letsencrypt/live/automation.example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/automation.example.com/privkey.pem;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers HIGH:!aNULL:!MD5;
    
        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
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
        }
    }
    

    Obtain SSL Certificate with Let's Encrypt

    sudo apt install certbot python3-certbot-nginx -y
    sudo certbot --nginx -d automation.example.com
    

    Certbot will automatically configure SSL and set up auto-renewal via a systemd timer. Verify the renewal is active:

    sudo systemctl status certbot.timer
    

    Step 5: Complete Initial Setup

    Navigate to https://automation.example.com in your browser. You will see the n8n setup screen prompting you to create an owner account. Set a strong password and enable two-factor authentication immediately after account creation.

    Post-Setup Configuration

    • Enable 2FA: Navigate to Settings > Personal and enable two-factor authentication
    • Configure email: Set up SMTP for execution alerts and password recovery via environment variables
    • Review execution retention: Confirm your data pruning settings are active to prevent unbounded database growth

    Self-Hosted n8n vs n8n Cloud: Cost Comparison

    The cost equation depends heavily on your workload and whether you count engineering time.

    Self-Hosted Costs (2026 Estimates)

    ComponentMonthly Cost
    VPS (4 vCPU, 8 GB RAM)$20-$40
    Storage (80 GB NVMe + backups)$5-$10
    Managed PostgreSQL (optional)$15-$30
    Maintenance time (~2 hrs/month)$200+ (opportunity cost)
    Total (with labor)$40-$280/month

    n8n Cloud Pricing (2026)

    PlanMonthly CostExecutionsActive Workflows
    Starter$19/month5,00010
    Pro$59/month25,00040

    When Self-Hosting Makes Sense

    Self-hosting is cheaper at small scale — a Hetzner CX22 VPS costs around €4.35/month for 2 vCPU and 4 GB RAM, which is sufficient for personal or small-team use. However, once you need high availability, backups, monitoring, and staff time, self-hosting costs can reach or exceed the $59/month Pro plan.

    The real value of self-hosting is not always cost savings. It is data residency control (keeping data in your jurisdiction), customization (adding custom nodes, modifying behavior), and no execution limits (you are constrained only by your hardware, not a credit system). If you run thousands of executions daily, self-hosting eliminates the per-execution cost that compounds quickly on Cloud plans.

    PostgreSQL vs SQLite: Why It Matters

    SQLite is n8n's default database for convenience, but every 2026 production guide recommends PostgreSQL. Here is why:

    Concurrency: SQLite uses file-level locking, which means only one write operation can occur at a time. With multiple workflows executing simultaneously, this creates contention and delays. PostgreSQL handles concurrent connections efficiently.

    Backups: SQLite backups require copying the entire database file, and if a workflow is executing during the copy, you risk capturing an inconsistent state. PostgreSQL supports online backups with tools like pg_dump and point-in-time recovery without stopping n8n.

    Scalability: If you later want to run multiple n8n instances behind a load balancer (queue mode), PostgreSQL is a requirement. SQLite cannot be shared across instances.

    Migration path: Moving from SQLite to PostgreSQL is possible but involves export-import steps. Starting with PostgreSQL from day one avoids this migration headache entirely.

    Performance Optimization for Production

    Once your instance is running, several optimizations can significantly improve throughput and reliability:

    Enable queue mode with Redis. For high-volume deployments, queue mode separates workflow execution into worker processes coordinated via Redis 6+. This allows horizontal scaling — add more n8n worker containers as your workload grows.

    Right-size your infrastructure. AI-heavy workflows that call LLM APIs and process large datasets need significantly more resources. Monitor CPU, RAM, and disk I/O, and scale vertically before adding complexity.

    Modularize workflows. Break large monolithic workflows into smaller, reusable sub-workflows. This improves parallelism, reduces memory pressure, and makes debugging easier when something fails.

    Implement retry logic. Use n8n's built-in retry nodes with exponential backoff instead of tight polling loops. This reduces unnecessary API calls and prevents cascading failures when an external service is temporarily unavailable.

    Backup and Disaster Recovery

    Your workflows and stored credentials are the most valuable assets in your n8n deployment. The application itself is easy to reinstall — but losing your database means losing everything.

    What to Back Up

    • PostgreSQL data: Use pg_dump for logical backups or managed DB automated snapshots
    • n8n application data directory: /home/node/.n8n (mounted to ./data in our compose file), which may contain local files and configuration
    • Docker Compose file and environment variables: Store your docker-compose.yml and a secure backup of all environment variables (especially N8N_ENCRYPTION_KEY)

    Backup Script Example

    #!/bin/bash
    # Run via cron daily
    BACKUP_DIR="/backups/n8n/$(date +%Y%m%d)"
    mkdir -p "$BACKUP_DIR"
    
    # PostgreSQL backup
    docker exec n8n-docker-postgres-1 pg_dump -U n8n n8n > "$BACKUP_DIR/n8n-db.sql"
    
    # Application data backup
    tar czf "$BACKUP_DIR/n8n-data.tar.gz" -C ~/n8n-docker data
    
    # Retain 30 days of backups
    find /backups/n8n -maxdepth 1 -type d -mtime +30 -exec rm -rf {} +
    
    # Upload to offsite storage (S3, Backblaze, etc.)
    # aws s3 sync "$BACKUP_DIR" "s3://your-bucket/n8n-backups/$(date +%Y%m%d)/"
    

    Test your restore process regularly — a backup you have never restored is not a backup you can rely on.

    Common Pitfalls and How to Avoid Them

    1. Using :latest image tag: Pin specific versions and upgrade deliberately. Unpinned images introduce breaking changes without warning.

    2. Exposing port 5678 directly: Always use a reverse proxy. Direct exposure increases your attack surface and bypasses SSL.

    3. No backup strategy: Set up automated daily backups and test restores. Data loss in production n8n means losing complex workflows that took hours to build.

    4. Under-provisioned hardware: 1 vCPU and 1 GB RAM will start n8n but workflows will stall under real load. Start at 4 vCPU and 8 GB RAM for production.

    5. Losing the encryption key: The N8N_ENCRYPTION_KEY is irreplaceable. Store it in a password manager or secrets vault alongside your database credentials.

    Conclusion

    Self-hosting n8n in production is straightforward with Docker and PostgreSQL, but it requires attention to security, backup, and performance from day one. The infrastructure cost ranges from under $10/month for personal use to $40-280/month for production deployments with managed services — but the real value is control over your data, no execution limits, and the ability to customize your automation stack.

    For businesses that need help setting up or optimizing their n8n deployment, ishchuk.eu offers AI automation consulting services, including n8n implementation, workflow design, and production hardening.

    Further Reading

    Frequently asked questions

    How much does it cost to self-host n8n?
    Self-hosting n8n costs between $5-10 per month for a basic VPS suitable for personal use, and $40-280 per month for a production deployment with managed PostgreSQL, backups, and maintenance time. The base n8n software is free under its fair-code license, so the only costs are infrastructure and your time. For comparison, n8n Cloud starts at $19/month for 5,000 executions.
    What are the system requirements for self-hosting n8n in 2026?
    The minimum requirements are 2 vCPUs, 2 GB RAM, 20 GB SSD, and either Docker 24+ or Node.js 20.19+. For production, 4 vCPUs, 8 GB RAM, 80 GB NVMe SSD, and PostgreSQL 15+ are recommended. AI-heavy workloads with large language model integrations may need 8+ vCPUs and 16+ GB RAM.
    Should I use SQLite or PostgreSQL when self-hosting n8n?
    PostgreSQL is strongly recommended for any production n8n deployment. SQLite works for quick testing but lacks the concurrency handling, reliable backup mechanisms, and multi-instance scalability that PostgreSQL provides. SQLite uses file-level locking that creates contention with simultaneous workflows, while PostgreSQL handles concurrent connections efficiently and supports online backups.
    How do I secure a self-hosted n8n deployment?
    Secure your n8n deployment by using a reverse proxy like Nginx or Caddy with Let's Encrypt SSL, binding n8n to localhost only, enabling secure cookies with N8N_SECURE_COOKIE=true, using SSH key authentication on your server, configuring a firewall with UFW to only allow ports 22, 80, and 443, installing Fail2Ban, and enabling two-factor authentication in n8n. Always pin your Docker image version and keep all components updated.
    How do I back up a self-hosted n8n instance?
    Back up your PostgreSQL database using pg_dump or managed database snapshots, back up the n8n application data directory at /home/node/.n8n, and securely store your N8N_ENCRYPTION_KEY since it is required to decrypt stored credentials. Run backups daily via cron, retain at least 30 days, upload to offsite storage, and test your restore process regularly.
    What is the N8N_ENCRYPTION_KEY and why is it important?
    The N8N_ENCRYPTION_KEY is a secret string that encrypts all stored credentials in your n8n database, including API keys, passwords, and connection tokens. If you lose this key, all stored credentials become permanently unrecoverable. Generate it using a command like openssl rand -hex 16 and store it in a password manager or secrets vault alongside your database credentials.