Skip to main content

Self-Hosting n8n: Workflow Automation 2026

·OSSAlt Team
n8nautomationself-hostingdockerguide
Share:

n8n is the open source Zapier alternative with 400+ integrations and a visual workflow builder. Self-hosting gives you unlimited workflows, no execution limits, and full control over your automation data.

Why Self-Host n8n

Zapier's pricing is consumption-based and can scale uncomfortably fast. The Starter plan at $19.99/month gives 750 tasks. The Professional plan at $49/month covers 2,000 tasks. For anyone running serious automations — syncing CRM data, processing webhooks, orchestrating marketing workflows — task limits become a constraint within months. Make (formerly Integromat) follows a similar operations-based model.

Self-hosting n8n costs the price of a VPS — a €4.50/month Hetzner server handles dozens of concurrent workflows with no task caps. Annual cost: approximately $54 versus Zapier's $240-$600. For data-intensive automation pipelines running thousands of executions per month, self-hosting saves $2,000+ per year.

Data privacy is the other major driver. Automation workflows often touch sensitive data: customer records from your CRM, payment notifications, user-generated content. When you run Zapier or Make, that data passes through their cloud infrastructure. Self-hosted n8n keeps every piece of data — every webhook payload, every API response — on your own server.

No execution caps, no step limits. n8n Cloud's community plan limits workflows to a maximum of 5 steps and 5 active workflows. Self-hosted n8n has no such restrictions. You can build arbitrarily complex workflows with as many nodes and parallel branches as your server can handle.

400+ integrations and custom nodes: n8n's node library covers every major SaaS product, and you can write custom JavaScript inside the Code node for anything not covered. Unlike no-code tools with locked-down logic, n8n lets you run arbitrary code within your workflows.

When NOT to self-host n8n: If your team is non-technical and needs a tool that IT doesn't have to maintain, Zapier's polished UX and reliable managed infrastructure are worth the cost. Also, n8n's encryption key must be backed up carefully — if you lose it, all stored credentials become unreadable. For teams that can't maintain that operational discipline, a managed service is safer.

Prerequisites

n8n is lighter than most tools in this guide — the minimum requirements are genuinely achievable on budget hardware. Still, choosing the right VPS provider for self-hosting affects your webhook response times and workflow execution reliability.

Server specs: 1 GB RAM works for development and light automation. For production with concurrent workflows, 2 GB RAM gives comfortable headroom. CPU matters for workflows that process large datasets or run expensive JavaScript in Code nodes. A 2 vCPU server handles most workloads without bottlenecking.

PostgreSQL vs SQLite: n8n defaults to SQLite for simplicity, but SQLite is not recommended for production. Concurrent workflow executions can cause SQLite write contention, leading to failed executions. The Docker Compose setup here uses PostgreSQL, which handles concurrent writes cleanly and scales to thousands of workflow executions per day.

Encryption key backup: Generate your N8N_ENCRYPTION_KEY with openssl rand -hex 32 and store it in a secure password manager immediately. This key encrypts all stored credentials (API keys, passwords, tokens). If you lose it — for example, by accidentally deleting the Docker volume — every integration credential becomes permanently unreadable and must be re-entered manually.

Operating system: Ubuntu 22.04 LTS. n8n's Docker image is tested on Ubuntu, and the webhook URL routing via Caddy follows standard patterns well-documented in the community.

SMTP for workflow notifications: Many n8n workflows send email notifications. Configure SMTP early so the Email node works without special attention when building workflows later.

Skills required: Basic Docker Compose familiarity and understanding of environment variables. Building workflows in n8n itself requires no coding, though JavaScript knowledge unlocks the full power of the Code node.

Requirements

  • VPS with 1 GB RAM minimum (2 GB recommended)
  • Docker and Docker Compose
  • Domain name (e.g., n8n.yourdomain.com)
  • 10+ GB disk

Step 1: Create Docker Compose

# docker-compose.yml
services:
  n8n:
    image: n8nio/n8n:latest
    container_name: n8n
    restart: unless-stopped
    ports:
      - "5678:5678"
    volumes:
      - n8n_data:/home/node/.n8n
    environment:
      - N8N_HOST=n8n.yourdomain.com
      - N8N_PORT=5678
      - N8N_PROTOCOL=https
      - WEBHOOK_URL=https://n8n.yourdomain.com/
      - N8N_ENCRYPTION_KEY=your-random-encryption-key
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_HOST=db
      - DB_POSTGRESDB_PORT=5432
      - DB_POSTGRESDB_DATABASE=n8n
      - DB_POSTGRESDB_USER=n8n
      - DB_POSTGRESDB_PASSWORD=your-strong-password
      - GENERIC_TIMEZONE=America/New_York
    depends_on:
      - db

  db:
    image: postgres:16-alpine
    container_name: n8n-db
    restart: unless-stopped
    volumes:
      - db_data:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=n8n
      - POSTGRES_USER=n8n
      - POSTGRES_PASSWORD=your-strong-password

volumes:
  n8n_data:
  db_data:

Step 2: Generate Encryption Key

# Generate a random encryption key (keep this safe!)
openssl rand -hex 32

Replace your-random-encryption-key in the compose file. This encrypts all stored credentials. If you lose this key, all saved credentials become unreadable.

Step 3: Start n8n

docker compose up -d

Step 4: Reverse Proxy (Caddy)

# /etc/caddy/Caddyfile
n8n.yourdomain.com {
    reverse_proxy localhost:5678
}
sudo systemctl restart caddy

Step 5: Initial Setup

  1. Open https://n8n.yourdomain.com
  2. Create your admin account
  3. Set up your first workflow

Step 6: Essential Configuration

Environment variables to consider:

VariablePurposeExample
N8N_ENCRYPTION_KEYEncrypts credentialsRandom 64-char hex
N8N_USER_MANAGEMENT_DISABLEDSingle user modetrue
EXECUTIONS_DATA_PRUNEAuto-delete old executionstrue
EXECUTIONS_DATA_MAX_AGEExecution retention168 (7 days)
N8N_METRICSEnable Prometheus metricstrue
N8N_DIAGNOSTICS_ENABLEDDisable telemetryfalse
N8N_TEMPLATES_ENABLEDShow workflow templatestrue

Step 7: Set Up SMTP (For Email Nodes)

Add to your environment:

N8N_EMAIL_MODE=smtp
N8N_SMTP_HOST=smtp.resend.com
N8N_SMTP_PORT=587
N8N_SMTP_USER=resend
N8N_SMTP_PASS=re_your_api_key
N8N_SMTP_SENDER=n8n@yourdomain.com
N8N_SMTP_SSL=true

Slack notification on form submission:

  1. Webhook Trigger → receives form data
  2. Set node → format message
  3. Slack node → post to channel

Daily database backup to S3:

  1. Cron Trigger → runs daily
  2. Execute Command → pg_dump
  3. AWS S3 → upload backup file

GitHub PR → Linear ticket:

  1. GitHub Trigger → on PR opened
  2. Set node → map fields
  3. Linear → create issue

Production Hardening

Execution pruning (prevent disk filling up):

EXECUTIONS_DATA_PRUNE=true
EXECUTIONS_DATA_MAX_AGE=168
EXECUTIONS_DATA_PRUNE_MAX_COUNT=10000

Backups:

# Database backup (daily cron)
docker exec n8n-db pg_dump -U n8n n8n > /backups/n8n-$(date +%Y%m%d).sql

# Credentials and workflows
docker cp n8n:/home/node/.n8n /backups/n8n-data-$(date +%Y%m%d)

Pair your local backups with automated server backups using restic to push encrypted snapshots to offsite storage. The PostgreSQL database contains all your workflow definitions and execution history — it's the critical thing to protect.

Updates:

docker compose pull
docker compose up -d

Monitoring:

  • Monitor port 5678 with Uptime Kuma
  • Enable Prometheus metrics for workflow monitoring
  • Set up alerts for failed executions

Resource Usage

WorkflowsRAMCPUDisk
1-201 GB1 core10 GB
20-1002 GB2 cores20 GB
100+4 GB4 cores50 GB

VPS Recommendations

ProviderSpecPrice
Hetzner2 vCPU, 4 GB RAM€4.50/month
DigitalOcean1 vCPU, 2 GB RAM$12/month
Linode1 vCPU, 2 GB RAM$12/month

Production Security Hardening

n8n stores API credentials and runs code that touches external services — it's an attractive target. The webhook endpoint is public-facing by design, which makes hardening especially important. Follow the comprehensive self-hosting security checklist alongside these n8n-specific measures.

UFW firewall: Block direct access to n8n's port 5678 — all traffic should go through Caddy.

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 deny 5678/tcp   # Block direct n8n access
sudo ufw enable

Fail2ban:

sudo apt install fail2ban -y

/etc/fail2ban/jail.local:

[sshd]
enabled = true
maxretry = 5
bantime = 3600
findtime = 600

Encryption key and secrets in .env: Never hardcode the encryption key in your Docker Compose file. Use a .env file:

# .env
N8N_ENCRYPTION_KEY=your-32-byte-hex-key
DB_POSTGRESDB_PASSWORD=your-strong-password
chmod 600 .env
echo ".env" >> .gitignore

Back up the encryption key separately from your server — store it in a password manager or secrets vault. The key is not stored in the database; it's read from the environment at startup. If the server is lost without the key, all credentials are gone permanently.

Disable SSH password auth: Edit /etc/ssh/sshd_config:

PasswordAuthentication no
PermitRootLogin no

Restart: sudo systemctl restart sshd

Automatic security updates:

sudo apt install unattended-upgrades -y
sudo dpkg-reconfigure --priority=low unattended-upgrades

n8n access controls: Enable n8n's built-in user management. Set N8N_USER_MANAGEMENT_DISABLED=false and create individual accounts for each team member rather than sharing a single login. This provides an audit trail of who created or modified which workflow.

Troubleshooting Common Issues

Webhooks work locally but not from external services

The WEBHOOK_URL environment variable must be the full public URL including the trailing slash: https://n8n.yourdomain.com/. If it's wrong, n8n generates incorrect webhook URLs when you create webhook triggers. Restart after fixing, then re-check the webhook URL shown in any Webhook node.

"Credentials not found" after container restart

If you changed the N8N_ENCRYPTION_KEY between restarts, credentials encrypted with the old key can't be decrypted. The key must remain constant for the lifetime of the n8n installation. Check that your .env file persists correctly and that the Docker volume containing /home/node/.n8n wasn't deleted. If credentials are truly lost, you'll need to re-enter them in n8n's credential manager.

PostgreSQL connection refused on startup

n8n starts before PostgreSQL is ready to accept connections. Add a healthcheck to the db service in your Docker Compose, or set N8N_SKIP_WEBHOOK_DEREGISTRATION_SHUTDOWN=true and let Docker's restart: unless-stopped handle recovery. Usually n8n's automatic retry handles this within 30 seconds — check docker logs n8n for "Connected to database" confirmation.

Disk fills up from execution logs

With EXECUTIONS_DATA_PRUNE disabled (the default), every workflow execution is stored forever in PostgreSQL. Enable pruning: EXECUTIONS_DATA_PRUNE=true and EXECUTIONS_DATA_MAX_AGE=168 (7 days in hours). To clean up existing data: go to n8n's Settings → Executions and bulk delete old executions, or run DELETE FROM execution_entity WHERE "startedAt" < NOW() - INTERVAL '7 days'; directly in PostgreSQL.

Email node fails with "Connection refused"

Verify your SMTP configuration by checking if port 587 is accessible: docker exec n8n nc -zv smtp.resend.com 587. Some VPS providers block outbound SMTP on port 25 and 587 by default (Hetzner requires a support request to unlock). Use port 465 (SSL) or Resend/Postmark's HTTP API as an alternative via n8n's HTTP Request node.

Ongoing Maintenance and Operations

n8n is one of the more pleasant self-hosted applications to maintain long-term. The operational surface is small — it's essentially one container plus a database — and the community is active with good troubleshooting resources.

Workflow organization. As your automation library grows, adopt a naming convention early. A good pattern: [Team/Project] - [What it does] - [Trigger type]. For example: Sales - New Lead → CRM + Slack - Webhook or DevOps - Deploy notify - Cron. Without consistent naming, finding the right workflow in a library of 50+ becomes time-consuming.

Error handling in workflows. Production workflows should handle errors gracefully. Add an Error Trigger node that catches failed executions and sends you a Slack or email notification with the workflow name and error message. Without this, failed workflows silently fail — you only discover the problem when someone notices something didn't happen. Go to n8n's SettingsError Workflow to set a global error handler.

Credential management hygiene. n8n stores API credentials encrypted with your N8N_ENCRYPTION_KEY. These credentials should be treated like passwords — rotate them annually and immediately when team members with access leave. When rotating credentials, update them in n8n's Credentials panel and test affected workflows before considering the rotation complete.

Execution log review. n8n logs every workflow execution with inputs, outputs, and timing. These logs are invaluable for debugging, but reviewing them manually doesn't scale. Use n8n's built-in filtering to review failed executions weekly: go to Executions and filter by status "Error." Most recurring failures have patterns — fix them at the source rather than repeatedly restarting failed runs.

Scaling workflow complexity. When workflows get complex (20+ nodes, multiple branches), break them into smaller sub-workflows called via n8n's Execute Workflow node. This makes individual pieces testable, reusable, and easier to debug. A common pattern: a "Router" workflow that receives a webhook and dispatches to specialized sub-workflows based on the event type.

Upgrading n8n safely. n8n releases updates frequently, including security patches. Before upgrading, check the n8n changelog for breaking changes (especially credential format changes or removed node parameters). The upgrade procedure is: stop n8n, pull the new image, start it — the database migrations run automatically. Keep one previous version available by tagging your current image before pulling the new one: docker tag n8nio/n8n:current n8nio/n8n:backup.

Webhook reliability. If external services (GitHub, Stripe, Slack) report webhook delivery failures, the most common cause is your server being temporarily unreachable. n8n doesn't have built-in webhook queuing — if your server is down when a webhook fires, the event is lost. For critical automations, implement idempotent retry logic on the sending side or consider deploying a lightweight webhook receiver (like a simple Express server) that persists events to a queue even when n8n is down.


Compare automation platforms on OSSAlt — integrations, pricing, and self-hosting options side by side.

See open source alternatives to n8n on OSSAlt.

The SaaS-to-Self-Hosted Migration Guide (Free PDF)

Step-by-step: infrastructure setup, data migration, backups, and security for 15+ common SaaS replacements. Used by 300+ developers.

Join 300+ self-hosters. Unsubscribe in one click.