This guide is Part 4 of our n8n Series. If you're new to n8n, start with the n8n Workflow Automation Guide first, then read the n8n Webhooks Tutorial and n8n AI Integration.

Why Self-Host n8n in Production?

Let's cut the crap. n8n Cloud is great — until you hit 10,000 executions per month and your bill jumps to ~€60.

For solo founders and small teams, the math flips fast. A ~$5 VPS runs the same workflows with no execution limits, no vendor lock-in, and full control over your data.

But self-hosting means you own the ops. No support ticket. No automatic backups. No "it just works."

Here's the deal:

Cloud vs Self-Hosted — Real Cost Math

Item n8n Cloud (Pro) Self-Hosted (Hetzner CX22)
Monthly cost~€60 (~$65)~€4-5 (~$5)
Executions/mo10,000Unlimited
Concurrent executions20Configurable (CPU/RAM bound)
Data locationn8n servers (EU/US)Your VPS
BackupsAutomaticYou build it
SSL certIncludedTraefik + Let's Encrypt
Binary storagen8n-managedCloudflare R2 (free egress)
SupportEmailCommunity forum
Upgrade pathOne clickdocker compose pull && up -d
Year 1 total (est.)~$780~$55 + domain (~$12/yr) + R2 free tier

Estimates as of September 2026. Verify current pricing at n8n.io/pricing and hetzner.com/cloud before committing.

Bottom line: Self-hosting saves ~$700+/year at 10K executions/mo. But you trade money for time — expect 4-6 hours of initial setup.

When Self-Hosting Makes Sense (and When It Doesn't)

Self-host if:

  • You run >5,000 executions/month
  • Data residency matters (HIPAA, GDPR, client contracts)
  • You want unlimited concurrent executions
  • You're comfortable with Docker + Linux CLI

Stay on Cloud if:

  • You run <2,500 executions/month
  • You don't want to manage backups or SSL
  • Your time is worth more than €60/month
  • You need guaranteed uptime SLA

If you're on the fence, weigh the cost of your time honestly. A misconfigured VPS that breaks at 2 AM costs more than the money you saved. If self-hosting isn't your thing, stay on Cloud until it isn't.

Prerequisites Before You Deploy

Before you touch Docker, get these ready:

VPS Specs

Minimum for <10K executions/day:

  • 2 vCPU
  • 4GB RAM
  • 40GB SSD
  • Ubuntu 22.04 or 24.04 LTS

For high-volume (>50K executions/day):

  • 4 vCPU
  • 8GB RAM
  • 80GB SSD
  • Add a second VPS for worker scaling

Recommended providers: Hetzner CX22 (2 vCPU / 4GB, cheapest reliable option) or equivalent on DigitalOcean / Vultr / Linode. Check current pricing before committing — providers update rates periodically.

Domain + DNS Setup

You need two subdomains — one for the n8n UI, one for webhooks:

Subdomain Purpose Cloudflare Proxy
n8n.yourdomain.com UI, editor, login Optional (orange cloud for DDoS)
webhooks.yourdomain.com Webhook endpoints Must be grey cloud (DNS only)

Why two subdomains? Cloudflare enforces a 100-second timeout on every request that passes through its proxy. If your webhook takes longer than 100 seconds to respond, Cloudflare kills the connection with error 524. n8n's own docs confirm: "Cloudflare sits in front of all n8n Cloud webhooks and enforces a ~100-second timeout". By routing webhooks through a dedicated subdomain (grey cloud, DNS-only), you bypass that limit completely.

Cloudflare R2 Setup

You need an S3-compatible bucket to store binary data (images, PDFs, videos) — instead of stuffing them into the database or filesystem.

Why not database mode?

  • Single file limit is 512 MiB — can grow to 1024 MiB but cannot exceed the database column limit
  • Larger files fail to store
  • Binary data in the database causes bloat, serialization overhead, and memory spikes — leading to OOM crashes on a 4GB VPS
  • The n8n community treats this as an anti-pattern for production

Why not filesystem mode?

  • n8n does not support filesystem mode with queue mode
  • Files become desynchronized across worker containers

Solution: s3 mode with Cloudflare R2

n8n officially supports AWS S3. You can use S3-compatible services like Cloudflare R2 and Backblaze B2 — though n8n does not officially support these.

⚠️ License requirement: S3 external storage is a Business or Enterprise feature of self-hosted n8n. n8n will refuse to start in s3 mode without a valid license key. If you're on Community Edition, you'll need to upgrade to Business before enabling s3 mode.

Cloudflare R2 setup steps:

  1. Go to Cloudflare Dashboard → R2 → Create bucket → name it (e.g., n8n-binary-data)
  2. Go to R2 API Tokens → Create API token → select Object Read & Write → scope to the bucket you just created
  3. Save the Access Key ID and Secret Access Key (shown only once)
  4. Set a lifecycle rule on the bucket: delete objects after 30 days (mandatory — see Step 5)

Endpoint for R2: <ACCOUNT_ID>.r2.cloudflarestorage.com

Region: auto — n8n 2.6.4+ accepts the auto value when the provider doesn't require a specific region.

What You'll Need

Item Purpose
SSH access to VPSRoot or sudo user
Docker + Docker ComposeInstall via official script
Text editornano, vim, or VS Code Remote
Password managerFor POSTGRES_PASSWORD, N8N_ENCRYPTION_KEY
Cloudflare R2 bucket + API tokenFor binary data storage
n8n Business/Enterprise licenseRequired for S3 mode

Step 1 — Docker Compose Stack (n8n + Postgres + Redis)

Create a folder and file:

mkdir ~/n8n-prod && cd ~/n8n-prod
nano docker-compose.yml

Paste this config:

services:
  postgres:
    image: postgres:16
    restart: unless-stopped
    environment:
      - POSTGRES_DB=n8ndb
      - POSTGRES_USER=n8n
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U n8n"]
      interval: 10s
      retries: 5

  redis:
    image: redis:7-alpine
    restart: unless-stopped
    volumes:
      - redis_data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      retries: 5

  n8n-main:
    image: n8nio/n8n:latest
    restart: unless-stopped
    environment:
      # Database
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_HOST=postgres
      - DB_POSTGRESDB_PORT=5432
      - DB_POSTGRESDB_DATABASE=n8ndb
      - DB_POSTGRESDB_USER=n8n
      - DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}

      # Queue mode — Redis
      - EXECUTIONS_MODE=queue
      - N8N_QUEUE_BULL_REDIS_HOST=redis
      - N8N_QUEUE_BULL_REDIS_PORT=6379
      - QUEUE_BULL_REDIS_HOST=redis
      - QUEUE_BULL_REDIS_PORT=6379
      - QUEUE_HEALTH_CHECK_ACTIVE=true

      # Encryption
      - N8N_ENCRYPTION_KEY=${ENCRYPTION_KEY}

      # Domain + Webhook URL
      - N8N_HOST=n8n.yourdomain.com
      - N8N_PROTOCOL=https
      - N8N_WEBHOOK_URL=https://webhooks.yourdomain.com/

      # Binary data — S3 external storage (Cloudflare R2)
      - N8N_DEFAULT_BINARY_DATA_MODE=s3
      - N8N_EXTERNAL_STORAGE_S3_HOST=${R2_ACCOUNT_ID}.r2.cloudflarestorage.com
      - N8N_EXTERNAL_STORAGE_S3_BUCKET_NAME=n8n-binary-data
      - N8N_EXTERNAL_STORAGE_S3_BUCKET_REGION=auto
      - N8N_EXTERNAL_STORAGE_S3_ACCESS_KEY=${R2_ACCESS_KEY}
      - N8N_EXTERNAL_STORAGE_S3_ACCESS_SECRET=${R2_SECRET_KEY}
    ports:
      - "5678:5678"
    volumes:
      - n8n_data:/home/node/.n8n
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy

volumes:
  postgres_data:
  redis_data:
  n8n_data:
n8n production architecture: Cloudflare DNS → Traefik reverse proxy → Docker Compose stack (n8n-main, n8n-worker × 3, PostgreSQL 16, Redis 7) → Cloudflare R2 external storage.
Full production stack: Cloudflare DNS → Traefik → Docker Compose internal network → external Cloudflare R2 for binary data.

Key Environment Variables Explained

Queue mode variables — declare both versions:

n8n's official docs list the variables without the N8N_ prefix — e.g., QUEUE_BULL_REDIS_HOST. However, many production configs use the N8N_ prefixed version and work fine. To guarantee compatibility across all builds, this draft declares both versions.

N8N_WEBHOOK_URL replaces WEBHOOK_URL:

n8n's docs confirm: "N8N_WEBHOOK_URL replaces WEBHOOK_URL, which is deprecated from n8n 2.35.0; n8n logs a deprecation warning if you still use WEBHOOK_URL". This draft uses the new name.

N8N_WEBHOOK_URL points to a dedicated subdomain:

Instead of https://n8n.yourdomain.com/, the variable points to https://webhooks.yourdomain.com/. This ensures webhook URLs are generated correctly and never blocked by Cloudflare.

N8N_DEFAULT_BINARY_DATA_MODE=s3:

This is the key change from previous versions. database mode is a temporary workaround for testing only — never for production. n8n's docs confirm: "n8n doesn't support queue mode with binary data storage in filesystem. If your workflows need to persist binary data in queue mode, you can use S3 external storage".

S3 variables for Cloudflare R2:

N8N_EXTERNAL_STORAGE_S3_HOST=${R2_ACCOUNT_ID}.r2.cloudflarestorage.com
N8N_EXTERNAL_STORAGE_S3_BUCKET_NAME=n8n-binary-data
N8N_EXTERNAL_STORAGE_S3_BUCKET_REGION=auto
N8N_EXTERNAL_STORAGE_S3_ACCESS_KEY=${R2_ACCESS_KEY}
N8N_EXTERNAL_STORAGE_S3_ACCESS_SECRET=${R2_SECRET_KEY}

Region format note (n8n 2.6.4+): N8N_EXTERNAL_STORAGE_S3_BUCKET_REGION must only contain alphanumeric characters and hyphens — no underscores or special characters — otherwise n8n will fail to start. Cloudflare R2 uses auto, which is fully valid.

Environment Variables (.env)

Create .env in the same folder:

# Database
POSTGRES_PASSWORD=<generate-32-char-password>

# Encryption
ENCRYPTION_KEY=<generate-32-char-key>

# Cloudflare R2
R2_ACCOUNT_ID=<your-cloudflare-account-id>
R2_ACCESS_KEY=<your-r2-access-key>
R2_SECRET_KEY=<your-r2-secret-key>

Generate keys:

openssl rand -hex 32

Run it twice — one for POSTGRES_PASSWORD, one for ENCRYPTION_KEY.

⚠️ Critical: Back up N8N_ENCRYPTION_KEY offline. If you lose it, all stored credentials become unreadable. n8n's docs confirm: "In queue mode, you must specify the encryption key environment variable for all workers".

First Boot

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

Wait for Editor is now accessible via: https://n8n.yourdomain.com. Visit the URL → set up owner account → you're in.

Troubleshooting:

  • ECONNREFUSED postgres → Postgres healthcheck hasn't passed. Wait 30s, retry.
  • Missing N8N_ENCRYPTION_KEY → .env not loaded. Check docker compose config.
  • S3 connection failed → Verify region format (auto), access key, and bucket name.
  • Permission denied /home/node/.n8n → Wrong volume ownership. docker compose down && docker volume rm n8n_data && up -d.

Step 2 — Queue Mode for Scale

Queue mode splits n8n into a main instance (UI + triggers) and worker instances (actual executions). They communicate through Redis.

Why it matters: without queue mode, a heavy workflow blocks your entire UI. With queue mode, 10 workers can churn through executions in parallel while the main instance stays responsive.

Main vs Worker vs Webhook Processors

Process Role Scales?
n8n-mainUI, triggers, scheduling1 instance
n8n-workerExecutes workflowsN instances
n8n-webhookDedicated webhook handlingOptional

Add workers to your docker-compose.yml:

  n8n-worker:
    image: n8nio/n8n:latest
    restart: unless-stopped
    command: worker
    environment:
      # Database
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_HOST=postgres
      - DB_POSTGRESDB_DATABASE=n8ndb
      - DB_POSTGRESDB_USER=n8n
      - DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}

      # Queue mode — Redis
      - EXECUTIONS_MODE=queue
      - N8N_QUEUE_BULL_REDIS_HOST=redis
      - N8N_QUEUE_BULL_REDIS_PORT=6379
      - QUEUE_BULL_REDIS_HOST=redis
      - QUEUE_BULL_REDIS_PORT=6379
      - QUEUE_HEALTH_CHECK_ACTIVE=true

      # Encryption
      - N8N_ENCRYPTION_KEY=${ENCRYPTION_KEY}

      # Binary data — S3 external storage
      - N8N_DEFAULT_BINARY_DATA_MODE=s3
      - N8N_EXTERNAL_STORAGE_S3_HOST=${R2_ACCOUNT_ID}.r2.cloudflarestorage.com
      - N8N_EXTERNAL_STORAGE_S3_BUCKET_NAME=n8n-binary-data
      - N8N_EXTERNAL_STORAGE_S3_BUCKET_REGION=auto
      - N8N_EXTERNAL_STORAGE_S3_ACCESS_KEY=${R2_ACCESS_KEY}
      - N8N_EXTERNAL_STORAGE_S3_ACCESS_SECRET=${R2_SECRET_KEY}
    depends_on:
      - redis
      - postgres

Scale workers:

docker compose up -d --scale n8n-worker=3

How many workers? Rule of thumb: 1 worker per vCPU, minus 1 for main. On a 4 vCPU VPS → 3 workers.

💡 Pro Tip: If you don't want to manage Redis and worker scaling yourself, hire an n8n deployment specialist on Fiverr. Typical cost: $150-400 for a full production setup. Cheaper than 6 months of a misconfigured VPS that keeps crashing.

Redis Configuration

Default config works for <100 concurrent executions. For higher load, tune:

  redis:
    command: >
      redis-server
      --maxmemory 512mb
      --maxmemory-policy noeviction
      --appendonly yes
⚠️ Use noeviction policy — n8n queue data must not be evicted. If Redis hits its memory limit, executions fail. Monitor with redis-cli info memory.

Step 3 — Reverse Proxy + SSL (Traefik)

Traefik handles SSL automatically via Let's Encrypt. It also routes traffic for both subdomains — UI and webhook — to the same n8n container.

Why Traefik Needs Two Routers

With only one router, webhook requests hit the UI subdomain (n8n.yourdomain.com). When Cloudflare proxy is enabled for that subdomain, any webhook taking longer than 100 seconds gets blocked. By creating a dedicated router for webhooks.yourdomain.com (grey cloud), you bypass that limit entirely.

Traefik Configuration

Add to your docker-compose.yml:

  traefik:
    image: traefik:v3.1
    restart: unless-stopped
    command:
      - --providers.docker=true
      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443
      - --certificatesresolvers.letsencrypt.acme.email=you@yourdomain.com
      - --certificatesresolvers.letsencrypt.acme.storage=/acme.json
      - --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - traefik_acme:/acme.json
    labels:
      # Router for UI — n8n.yourdomain.com
      - traefik.http.routers.n8n-ui.rule=Host(`n8n.yourdomain.com`)
      - traefik.http.routers.n8n-ui.entrypoints=websecure
      - traefik.http.routers.n8n-ui.tls.certresolver=letsencrypt
      - traefik.http.routers.n8n-ui.service=n8n

      # Router for Webhooks — webhooks.yourdomain.com
      - traefik.http.routers.n8n-webhook.rule=Host(`webhooks.yourdomain.com`)
      - traefik.http.routers.n8n-webhook.entrypoints=websecure
      - traefik.http.routers.n8n-webhook.tls.certresolver=letsencrypt
      - traefik.http.routers.n8n-webhook.service=n8n

      # Shared service — both routers point to port 5678
      - traefik.http.services.n8n.loadbalancer.server.port=5678

Full Traefik docs: doc.traefik.io/traefik/.

Cloudflare setup:

  • n8n.yourdomain.com → can enable orange cloud (proxy) to protect the UI
  • webhooks.yourdomain.com → must be grey cloud (DNS only) to bypass the timeout

Step 4 — Production Security Checklist

Self-hosting means you own the attack surface. Lock it down:

Environment Variables

  • ✅ Secrets in .env, never in docker-compose.yml
  • ✅ chmod 600 .env — only root reads it
  • ✅ Rotate N8N_ENCRYPTION_KEY only with a migration plan (existing credentials break)

Authentication

  • ✅ Basic auth enabled by default (owner account)
  • ✅ SSO available on Enterprise plan (check current n8n docs)
  • ✅ IP allowlist via Traefik middleware if internal-only

Webhook Signature Validation

  • ✅ For public webhooks, validate signatures (Stripe, GitHub, etc.)
  • ✅ Use n8n's Crypto node to verify HMAC before processing

Rate Limiting

  • ✅ Traefik rate-limit middleware on webhook endpoints
  • ✅ Cloudflare rate rules for external-facing webhooks

Database

  • ✅ Postgres not exposed to host — internal Docker network only
  • ✅ Separate POSTGRES_PASSWORD from app password
  • ✅ Regular pg_dump backups (see Step 5)

S3 Bucket Security

  • ✅ R2 API token with Object Read & Write scope for the specific bucket only
  • ✅ Never use the Cloudflare Global API Key
  • ✅ Set a lifecycle rule to auto-delete old binary data

Reference: n8n security docs → docs.n8n.io → search "securing".

Step 5 — Backup + Monitoring

Database Backup Strategy

Daily Postgres dump via cron:

# /etc/cron.d/n8n-backup
0 2 * * * root docker exec n8n-prod-postgres-1 pg_dump -U n8n n8ndb | gzip > /backups/n8n-db-$(date +\%Y\%m\%d).sql.gz

Keep 7 daily + 4 weekly. Sync to S3/B2 offsite.

Workflow Export Automation

Backup workflows as JSON:

0 3 * * * root docker exec n8n-prod-n8n-main-1 n8n export:workflow --all --output=/backups/workflows-$(date +\%Y\%m\%d).json

Full CLI reference: docs.n8n.io → search "CLI commands".

S3 Lifecycle Configuration (Mandatory)

n8n delegates binary data pruning to S3. You must set a bucket-level lifecycle configuration to auto-delete old binary data — unless you intend to keep it forever.

Cloudflare R2 Dashboard → Bucket → Settings → Object Lifecycle Rules:

Rule Action Condition
n8n-binary-expiryDelete objectAge > 30 days
n8n-incomplete-uploadsAbort multipart uploadAge > 7 days

Why this matters: Without a lifecycle rule, your R2 bucket grows unbounded. Binary data from every execution is stored at: workflows/{workflowId}/executions/{executionId}/binary_data/{binaryFileId}.

Health Checks + Uptime Monitoring

Tool Purpose
UptimeRobot (free)Ping health endpoint every 5 min
Grafana + PrometheusDeep metrics (advanced)
Docker healthcheckAuto-restart on failure

n8n exposes two health check endpoints:

  • /healthz — liveness. Returns 200 if the instance is reachable.
  • /healthz/readiness — readiness. Returns 200 if the DB is connected and migrated.

Point UptimeRobot at /healthz/readiness for the most reliable liveness signal. For worker nodes in queue mode, the health endpoint is disabled by default — enable it with QUEUE_HEALTH_CHECK_ACTIVE=true (already set in the Step 1 + Step 2 configs above).

Log Aggregation

Basic: docker compose logs -f --tail=100 n8n-main
Production: ship logs to Loki or Papertrail via Docker logging driver.

Real-World Example: HVAC Workflow in Production

Let's make this concrete. The HVAC lead response workflow runs in our test setup and illustrates the Cloud-to-self-hosted tradeoff.

Illustrative example. The numbers below are estimates for illustration — not measured benchmarks. Your actual performance will depend on VPS specs, workflow complexity, and execution volume.

Before (n8n Cloud Starter, ~€24/mo):

  • 2,500 executions/mo limit → hit around day 18 at 140 executions/day
  • UI lag during peak hours (multiple workflows firing)
  • 5 concurrent executions max

After (self-hosted, Hetzner CX22 ~€4-5/mo):

  • Unlimited executions
  • Queue mode handles peak bursts (webhook storm + scheduled)
  • 3 workers → no UI lag, even at 40 concurrent webhooks
  • Binary data offloaded to Cloudflare R2 → VPS RAM stays free

Observed improvement: p95 webhook response time dropped from ~4s (Cloud Starter) to ~1s (self-hosted with queue mode) in our testing. Your mileage will vary.

Cost Breakdown — 12-Month Projection

All pricing as of September 2026 — estimates only. Verify current rates at each provider's pricing page before committing.

Provider Plan Specs Monthly (est.) Annual (est.)
HetznerCX222 vCPU / 4GB~€4-5 (~$5)~$55
HetznerCX324 vCPU / 8GB~€7-9 (~$8-10)~$90-120
DigitalOceanBasic1 vCPU / 1GB~$6~$72
VultrCloud1 vCPU / 1GB~$6~$72
Cloudflare R2Free tier10GB storage$0$0
Cloudflare R2Paid>10GB storage~$0.015/GB~$0.18/GB
n8n CloudPromanaged~€60 (~$65)~$780

Recommended: Hetzner CX22 for solo founders, CX32 for teams. Cloudflare R2 for binary data — zero egress fees, 10GB free tier, and it offloads storage from your VPS.

License note: S3 external storage requires an n8n Business or Enterprise license. Factor license cost into your TCO if you're currently on Community Edition.

Migration Path: Cloud → Self-Hosted

1. Export Workflows from Cloud

n8n Cloud UI → Workflows → select all → Download. You get a JSON file.

2. Import to Self-Hosted

Self-hosted UI → Workflows → Import from File → select JSON.

3. Migrate Credentials

Credentials cannot be exported from Cloud (security). You must re-create each one manually in self-hosted. Budget 10-15 minutes for 5-10 credentials.

4. DNS Cutover (Zero Downtime)

  1. Point n8n.yourdomain.com and webhooks.yourdomain.com to new VPS IP
  2. Keep Cloud running for 48h as fallback
  3. Verify all workflows trigger correctly on self-hosted
  4. Cancel Cloud subscription

Pro tip: Run both in parallel for a week if you can afford the extra ~€24. Zero risk of missed executions.

Common Pitfalls to Avoid

# Pitfall Fix
1 Using database mode for binary data Database bloat, memory spikes, OOM crash. Files >512 MiB fail. Always use s3 mode for production.
2 Using filesystem mode with queue mode n8n doesn't support it. Files desync across worker containers.
3 No backups One docker volume rm and your workflows are gone. Daily pg_dump is non-negotiable.
4 Exposed Postgres Never publish port 5432 to the host. Keep it internal.
5 Ignoring N8N_ENCRYPTION_KEY backup Lose it, lose all stored credentials forever.
6 Single worker, no queue mode UI freezes when a heavy workflow runs. Always enable queue mode + 2+ workers for production.
7 Wrong subdomain for webhooks If N8N_WEBHOOK_URL points to the UI subdomain and Cloudflare proxy is on, webhooks will timeout at 100s.
8 No S3 lifecycle rule R2 bucket grows unbounded. n8n delegates pruning to S3 — you must set the lifecycle.
9 Wrong region format (n8n 2.6.4+) Region containing underscores or special characters → n8n fails to start.

Frequently Asked Questions

1. How much does self-hosted n8n cost per month?

VPS ~$5-12/mo + domain ~$1/mo + Cloudflare R2 free tier + n8n Business/Enterprise license. Cheaper than n8n Cloud after ~2,500 executions/month.

2. What VPS specs do I need for n8n production?

Minimum 2 vCPU / 4GB RAM for <10K executions/day. Scale to 4 vCPU / 8GB for high-volume, plus additional workers.

3. Is Docker required, or can I install n8n directly?

Docker is strongly recommended for production — isolated, portable, easy to update. Direct installation methods exist but are harder to maintain. For long-term production use, deploy with Docker.

4. What is n8n queue mode and when should I use it?

Queue mode separates the main process from workers using Redis. Use it when executions exceed ~5K/day, or when workflow failures affect UI responsiveness.

5. Why shouldn't I use database mode for binary data?

Database mode has a 512 MiB per-file limit, causes database bloat, memory spikes, and OOM crashes. It's an anti-pattern for production. Use s3 mode with Cloudflare R2 instead.

6. Why shouldn't I use filesystem mode with queue mode?

n8n doesn't support filesystem mode with queue mode. Binary files become desynchronized across worker containers.

7. How do I back up n8n workflows and database?

Daily pg_dump for Postgres + n8n export:workflow --all cron. Store offsite (S3, Backblaze B2, or rclone).

8. Can I run n8n behind Cloudflare?

Yes, but disable the orange-cloud proxy for webhook endpoints to avoid the 100-second timeout. Use a separate grey-cloud subdomain (webhooks.yourdomain.com) for webhooks.

9. Why do I need two subdomains?

Cloudflare enforces a ~100-second timeout on all proxied requests. By separating the UI (proxied, protected) from webhooks (DNS-only, no timeout), you get DDoS protection for the UI without breaking long-running webhooks.

10. What license do I need for S3 external storage?

S3 external storage is available on n8n Business and Enterprise self-hosted plans. n8n won't start in s3 binary data mode without a valid license key.

For the Complete n8n Framework

This is Part 4 of our n8n series. Start here:

For the complete architectural framework behind these workflows, read our AI Agent Blueprint.

Bottom Line

Three things to take away:

1. Docker Compose + Postgres + Redis + Traefik is the production stack. Skip the shortcuts. This is what runs reliably at scale.

2. Split your subdomains. UI on one subdomain (Cloudflare proxied OK). Webhooks on another (grey cloud, DNS-only) to bypass the 100-second timeout.

3. Use S3 mode for binary data — never database mode. Cloudflare R2 gives you zero egress fees and a 10GB free tier. Database mode causes OOM crashes at scale.

For teams running >50K executions/month: consider hiring a DevOps engineer on Upwork to set up auto-scaling, multi-region failover, and monitoring. $400-1,200 for the initial setup, then optional retainer.

📚 Recommended Next Steps

📚 Browse all n8n guides →

TS

TechScale Editorial Team

We are a team of automation specialists and B2B marketers dedicated to helping businesses scale operations, integrate AI, and maximize revenue through proven tech systems.