---
title: "How to Self-Host n8n: Complete Production Setup Guide"
url: https://ishchuk.eu/blog/how-to-self-host-n8n-complete-production-setup-guide
published: 2026-07-16T11:03:54.000Z
updated: 2026-07-16T11:03:57.024Z
tags: [n8n, self-hosting, docker, automation, workflow-automation, devops]
---

# 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:

| Resource | Minimum (Testing) | Recommended (Production) | AI-Heavy Workloads |
|----------|-------------------|--------------------------|-------------------|
| CPU | 2 vCPUs | 4 vCPUs | 8+ vCPUs |
| RAM | 2 GB | 8 GB | 16+ GB |
| Storage | 20 GB SSD | 80 GB NVMe SSD | 160+ GB NVMe |
| Database | SQLite | PostgreSQL 15+ | PostgreSQL 15+ |
| Runtime | Docker 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

```bash
# 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

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

### docker-compose.yml

```yaml
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

```bash
# 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

```bash
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

```bash
sudo apt install nginx -y
```

### Nginx Configuration

```nginx
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

```bash
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:

```bash
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)

| Component | Monthly 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)

| Plan | Monthly Cost | Executions | Active Workflows |
|------|-------------|------------|-----------------|
| Starter | $19/month | 5,000 | 10 |
| Pro | $59/month | 25,000 | 40 |

### 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

```bash
#!/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](https://ishchuk.eu) offers AI automation consulting services, including n8n implementation, workflow design, and production hardening.

## Further Reading

- [n8n vs Zapier vs Make: Which Automation Platform Wins in 2026?](https://ishchuk.eu/blog/n8n-vs-zapier-vs-make-which-automation-platform-wins-in-2026)
- [AI Agents vs Workflow Automation: Which Should Your Business Actually Use?](https://ishchuk.eu/blog/ai-agents-vs-workflow-automation-which-should-your-business-use-in-2026)
- [How to Choose the Right LLM for Your AI Agent Stack](https://ishchuk.eu/blog/how-to-choose-the-right-llm-for-your-ai-agent-stack-a-2026-decision-framework)


## FAQ

### 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.