<!-- OSSAlt AI-readable guide source -->
<!-- Canonical: https://ossalt.com/guides/self-hosting-guide-n8n-2026 -->
<!-- Raw Markdown: https://ossalt.com/guides/self-hosting-guide-n8n-2026/raw.md -->
<!-- Source path: content/guides/self-hosting-guide-n8n-2026.mdx -->

---
og_image: "/images/guides/self-hosting-guide-n8n-2026.webp"
title: "Self-Hosting n8n: Workflow Automation 2026"
description: "Deploy n8n on your own VPS with Docker — PostgreSQL backend, credentials encryption, webhooks, and production tips for self-hosted automation in 2026."
date: "2026-03-08"
author: "OSSAlt Team"
tags: ["n8n", "automation", "self-hosting", "docker", "guide"]
tier: 1
---

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](/guides/self-hosting-vps-comparison-2026) 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

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

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

```bash
docker compose up -d
```

## Step 4: Reverse Proxy (Caddy)

```
# /etc/caddy/Caddyfile
n8n.yourdomain.com {
    reverse_proxy localhost:5678
}
```

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

| Variable | Purpose | Example |
|----------|---------|---------|
| `N8N_ENCRYPTION_KEY` | Encrypts credentials | Random 64-char hex |
| `N8N_USER_MANAGEMENT_DISABLED` | Single user mode | `true` |
| `EXECUTIONS_DATA_PRUNE` | Auto-delete old executions | `true` |
| `EXECUTIONS_DATA_MAX_AGE` | Execution retention | `168` (7 days) |
| `N8N_METRICS` | Enable Prometheus metrics | `true` |
| `N8N_DIAGNOSTICS_ENABLED` | Disable telemetry | `false` |
| `N8N_TEMPLATES_ENABLED` | Show workflow templates | `true` |

## Step 7: Set Up SMTP (For Email Nodes)

Add to your environment:
```env
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
```

## Step 8: Popular Workflow Examples

**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):
```env
EXECUTIONS_DATA_PRUNE=true
EXECUTIONS_DATA_MAX_AGE=168
EXECUTIONS_DATA_PRUNE_MAX_COUNT=10000
```

**Backups:**
```bash
# 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](/guides/automated-server-backups-restic-rclone-2026) 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:**
```bash
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

| Workflows | RAM | CPU | Disk |
|-----------|-----|-----|------|
| 1-20 | 1 GB | 1 core | 10 GB |
| 20-100 | 2 GB | 2 cores | 20 GB |
| 100+ | 4 GB | 4 cores | 50 GB |

## VPS Recommendations

| Provider | Spec | Price |
|----------|------|-------|
| Hetzner | 2 vCPU, 4 GB RAM | €4.50/month |
| DigitalOcean | 1 vCPU, 2 GB RAM | $12/month |
| Linode | 1 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](/guides/self-hosting-security-checklist-2026) alongside these n8n-specific measures.

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

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

```bash
sudo apt install fail2ban -y
```

`/etc/fail2ban/jail.local`:

```ini
[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:

```bash
# .env
N8N_ENCRYPTION_KEY=your-32-byte-hex-key
DB_POSTGRESDB_PASSWORD=your-strong-password
```

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

```bash
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 **Settings** → **Error 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](https://www.ossalt.com) — integrations, pricing, and self-hosting options side by side.*

*See open source alternatives to n8n on [OSSAlt](https://www.ossalt.com/alternatives/n8n).*
