Who is this for?
You build things for a living and you need your automation to hold up in production. This guide is for developers, sysadmins and small teams who want n8n hosting on their own VPS with predictable performance and real control. If Linux and Docker are part of your week and you prefer clear configs over mystery boxes you are in the right place.
It fits when you:
- want to self host n8n on a VPS without hand-holding
- need Docker Compose with a clean reverse proxy and SSL
- care about backups, quick restores and low maintenance
- expect to scale from single node to queue mode with Redis and PostgreSQL
- must keep data close to home for privacy or compliance
TLDR: you rely on automation and you want it stable, secure and fast. Oh, and n8n is amazing.
What this guide covers
You will get a practical path to run n8n on a VPS from first boot to day-2 operations. We start with architecture choices then move through a working Docker Compose stack, a minimal Caddy or Nginx proxy, and the environment variables that make webhooks behave behind HTTPS. We compare PostgreSQL vs SQLite for real workloads, explain queue mode with Redis, and show how to size a box so executions do not thrash.
From there we cover backups that actually restore, routine monitoring, performance tuning, and safe upgrades so you avoid breaking running flows. Troubleshooting notes are included for the issues you will actually meet like wrong webhook URLs, idle workers or disks filling overnight. The tone is practical and the configs are ready to paste.
What n8n is and when self-hosting makes sense
n8n is an open-source workflow automation engine. You stitch together nodes that talk to APIs, webhooks, databases, queues and files. The editor runs in the browser and the runtime executes your flows either inline or on workers in queue mode. You can write code where needed and store credentials encrypted at rest.
Self-hosting makes sense when you want fixed costs, private networking and freedom to integrate with the rest of your stack. Run it next to your apps, connect to internal services over a VPN, tune PostgreSQL for your history needs, and decide how backups and retention work. If you are moving from Zapier or Make and you need more control or better pricing over time, a self-hosted n8n VPS is the natural next step.
Plan the deployment
Capacity and sizing
Start small then grow with data. A good baseline for self-host n8n is 2 vCPU and 4 GB RAM with fast NVMe SSD. If your flows pull large payloads or run in parallel, move to 4 vCPU and 8 GB RAM. Keep at least 40 to 80 GB free so logs, database pages and snapshots do not fight for space. If you plan to run heavy OCR, image work or big transforms, budget extra CPU or a separate worker pool.
Region and latency
Place the VPS near the services you call most. Webhooks for payments or Git events benefit from low latency paths. If your users sit in the EU, host in the EU. If flows pull big objects from a bucket, place compute near storage.
Network and DNS
Decide the public hostname before you boot. Webhook URLs and OAuth redirects must point at a stable HTTPS domain, for example https://automation.example.com
. Add an A or AAAA record to your VPS, keep a short DNS TTL during setup then raise it when stable.
Architecture choices
Single-node runtime
The editor and workflow executions run in one service. It is simple to operate and fine for pilots or small teams. Heavy jobs can slow the editor during spikes since both share memory and CPU.
Queue mode with workers
The editor stays light, pending jobs sit in Redis and workers pull jobs to execute. This isolates heavy workloads, improves responsiveness and lets you scale horizontally by adding workers. The main service accepts timers and webhooks then hands execution IDs to Redis, workers fetch from Redis and use the database to load workflow data then write results back. This path is the recommended way to scale n8n under load.
Database and binary data
SQLite vs PostgreSQL
By default n8n uses SQLite to store workflows, credentials and past executions. PostgreSQL is also supported and is the right pick for production since it handles concurrency and larger histories better.
Binary data modes
By default n8n keeps binary data in memory. For large files that can cause pressure, so single-node deployments often switch to N8N_DEFAULT_BINARY_DATA_MODE=filesystem
to write binaries to disk. If you use queue mode keep the default since filesystem mode is not supported with queue workers. Enterprise users can move binary data to external storage via supported plugins.
Environment variables that matter
These variables control URLs, security, database access and execution behavior. Place them in a .env
file kept off public repos.
# public URLs
N8N_HOST=automation.example.com
N8N_PROTOCOL=https
WEBHOOK_URL=https://automation.example.com/
# editor URL
N8N_EDITOR_BASE_URL=https://automation.example.com/
# port inside the container
N8N_PORT=5678
# behind reverse proxy
N8N_PROXY_HOPS=1
# security
N8N_SECURE_COOKIE=true
N8N_ENCRYPTION_KEY=<32-byte-random-hex>
# database (Postgres)
DB_TYPE=postgresdb
DB_POSTGRESDB_HOST=postgres
DB_POSTGRESDB_DATABASE=n8n
DB_POSTGRESDB_USER=n8n
DB_POSTGRESDB_PASSWORD=<change-me>
# binary data (single-node only)
N8N_DEFAULT_BINARY_DATA_MODE=filesystem
N8N_BINARY_DATA_STORAGE_PATH=/files
# telemetry
N8N_DIAGNOSTICS_ENABLED=false
N8N_PERSONALIZATION_ENABLED=false
When n8n sits behind a reverse proxy, set WEBHOOK_URL
so the editor shows correct webhook links and downstream services register the right callback address. Forward the usual X-Forwarded-*
headers at the last proxy hop.
A clean Docker Compose baseline
This stack gives you a secure single-node setup with Caddy handling HTTPS, PostgreSQL for durability and volumes for persistence. It is a good start for n8n VPS hosting on any provider.
version: "3.9"
services:
n8n:
image: n8nio/n8n:latest
env_file: .env
restart: unless-stopped
depends_on:
- postgres
ports:
- "127.0.0.1:5678:5678"
volumes:
- n8n_data:/home/node/.n8n
- n8n_files:/files
caddy:
image: caddy:2
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
- caddy_config:/config
postgres:
image: postgres:16
restart: unless-stopped
environment:
POSTGRES_USER: n8n
POSTGRES_PASSWORD: ${DB_POSTGRESDB_PASSWORD}
POSTGRES_DB: n8n
volumes:
- pg_data:/var/lib/postgresql/data
volumes:
n8n_data: {}
n8n_files: {}
caddy_data: {}
caddy_config: {}
pg_data: {}
Caddyfile for automatic TLS with a simple reverse proxy:
automation.example.com {
reverse_proxy n8n:5678
}
Point DNS to the VPS then bring it up with docker compose up -d
. Caddy will fetch a certificate from Let’s Encrypt and keep it renewed. The editor will be available at your HTTPS domain.
Queue mode with Redis and workers
When you need concurrency or isolation move to queue mode. Add Redis then a worker service. Keep the editor service at one replica.
.env additions for queue mode
EXECUTIONS_MODE=queue
QUEUE_BULL_REDIS_HOST=redis
QUEUE_BULL_REDIS_PORT=6379
# for TLS or cluster see QUEUE_BULL_REDIS_TLS and QUEUE_BULL_REDIS_CLUSTER_NODES
Compose services to add
redis:
image: redis:7
restart: unless-stopped
worker:
image: n8nio/n8n:latest
env_file: .env
restart: unless-stopped
command: n8n worker
depends_on:
- redis
- postgres
Scale workers with docker compose up -d --scale worker=4
. Workers share the same database and respect the same credentials. If you need Redis over TLS or cluster, use the specific variables for Bull’s client to connect to a cluster, not the single host and port.
Reverse proxy details that prevent head-scratching
Headers and scheme
On the last proxy hop set X-Forwarded-For
, X-Forwarded-Host
and X-Forwarded-Proto
. In n8n set N8N_PROXY_HOPS=1
so it trusts the incoming headers. If the editor shows webhook links with the wrong scheme or port, fix N8N_PROTOCOL
, N8N_HOST
and WEBHOOK_URL
then restart the service.
Nginx alternative
If you prefer Nginx, allow larger client_max_body_size
for file uploads, bump proxy timeouts for long-running requests and forward the same X-Forwarded-*
headers. Certbot or a managed certificate solves TLS if you do not use Caddy.
Security hardening
Expose only 80 and 443 to the world. Lock SSH to key authentication with a firewall rule that limits source IPs if possible. Keep the OS updated on a schedule. Use a strong N8N_ENCRYPTION_KEY
and never commit .env
to public repos. Require strong passwords for the editor or set up SSO in larger teams. For public webhooks use provider signatures or allowlists where available. Rotate secrets when staff changes.
Backups and disaster recovery
Protect three layers then test restores regularly. Back up the PostgreSQL database with nightly pg_dump
to off-box storage with encryption. Persist the /home/node/.n8n
application directory which holds credentials, workflow JSON and settings. If you run single-node with filesystem binary data, persist that path too. Add periodic full VPS snapshots so you have a fast rollback path after risky changes. Rehearse a restore on a throwaway VPS so you own the steps before you need them.
Monitoring and alerting
What to track
CPU, RAM, disk usage, Postgres connections, Redis ops, queue depth, container restarts, webhook response times and SSL expiry. Alert on rate of change not only absolute limits. Rising queue time or growing Postgres connections tell you more than raw CPU.
Practical stack
Use Uptime Kuma for external checks. Add a Prometheus node exporter and a container metrics exporter then visualize with Grafana. If the database gets busy, run a Postgres exporter and watch connections, checkpoint intervals and table bloat. Keep log retention reasonable so a chatty node does not fill the disk overnight.
Performance tuning
Prefer PostgreSQL for production so concurrent executions do not block each other. Trim execution history on a schedule if you do not need long retention. In queue mode run several small workers rather than one huge worker. This isolates spikes and helps the kernel schedule fairly. If one workflow is noisy, pin it to a dedicated worker by label or by running a separate stack in the same VPS. If most wall time is spent waiting on remote APIs, more workers help. If CPU is saturated during transforms, scale vertically or move heavy steps to a service built for that job.
Upgrades and safe change management
Clone the stack to a staging VPS with a test domain. Pull new images and run smoke tests. In production drain workers so long jobs finish then roll workers one by one. Roll the editor last. Keep the previous image tag ready for rollback. After upgrades watch logs and metrics for a while before you leave it alone.
Troubleshooting
Webhook URLs show the wrong host or scheme
Fix N8N_HOST
, N8N_PROTOCOL
and WEBHOOK_URL
then restart. Confirm the proxy forwards the right headers. If you changed variables inside a container shell, remember that values vanish when the container restarts, so set them in .env
or the compose file.
Credentials disappear after a rebuild
You did not persist /home/node/.n8n
. Add the volume then restore from backup. Avoid deleting volumes on docker compose down
unless you really intend to wipe data.
Workers stay idle while jobs queue
Confirm EXECUTIONS_MODE=queue
, Redis connectivity and that main and workers use the same database. If Redis requires TLS or you use a cluster, set the specific queue variables for that topology.
Large uploads fail
Increase proxy body size and upstream timeouts. Check free disk space on the VPS then retry.
Disk fills overnight
Execution logs or container logs grew. Prune old runs, rotate logs and move binaries out of database storage in single-node mode. In queue mode keep the default binary mode since filesystem mode is not supported.
Cost planning without surprises
Self-hosting cost depends on the VPS plan, storage, snapshots and engineering time. A lean setup for internal automation often fits on 2 vCPU and 4 GB RAM. Production with busy APIs or many parallel flows prefers 4 vCPU and 8 GB RAM. Budget for off-box backups, a logging target and maybe a small metrics VM if you do not want them on the same host.
Use-case cookbook
Payment webhook to CRM
Receive a signed webhook from your gateway, enrich from a customer API, update the CRM then notify a chat channel. Add a short delay when the CRM rate-limits writes so you do not get 429s. Store the raw webhook body for a short time to replay in staging if you need to debug.
API to warehouse sync
Poll a REST endpoint, transform JSON, write to Postgres with the built-in node then export to your warehouse tool. Deduplicate on a stable key so you do not re-insert rows. A nightly compaction job keeps tables tidy.
Image intake
Accept a file upload, write to object storage, trigger an external processor, write metadata back to a table. Keep binaries out of the database so backups stay small.
Licensing in plain terms
n8n is under the Sustainable Use License. You can use, modify and self-host it for your own internal business use or personal projects. Reselling it as a hosted service requires a commercial agreement with n8n. If your plan includes embedding or resale, read the license and talk to the vendor before you launch.
Where a LumaDock VPS fits
You can run this on any Linux VPS…
But if you want a clean start with less base work, LumaDock offers KVM VPS plans with triple-replicated NVMe storage, always-on DDoS protection, built-in firewall management, dedicated IPv4 and unmetered bandwidth. These VMs are specifically designed for n8n and come with pre-installed Docker and Docker Compose templates.
You get root SSH access and can change any part of the stack. Bucharest and Paris run on modern AMD EPYC CPUs. Frankfurt and London run on enterprise Intel Xeon Gold.
Pricing starts at $1.49 per month with a 30-day refund window. LumaDock is operated by LifeinCloud, ISO-27001 certified and aligned with GDPR practices.
Step-by-step: from single-node to queue mode
Prepare
Make sure Postgres is running with its data on a volume. Add Redis to the compose file. Take a database backup and a snapshot so you have a safety net.
Switch execution mode
Set EXECUTIONS_MODE=queue
in .env
. Add at least one worker service that runs n8n worker
. Keep the editor as a single process.
Test
Trigger a workflow that takes a few seconds. Check that a job lands in Redis and a worker pulls it. Watch worker logs and the editor for status updates.
Scale
Increase workers to match concurrency requirements. Track CPU, memory and database connections as you scale. If Redis or Postgres latency rises, lift plan size or separate them.
Advanced topics you explore
Redis topologies
Use TLS if your security model requires it, or cluster when you need high availability. n8n exposes variables to connect to a Redis Cluster via the Bull client.
PostgreSQL care and feeding
Set connection limits, watch autovacuum, keep checkpoint intervals healthy and partition large execution tables if they grow fast. A weekly maintenance window for reindex or vacuum on busy tables keeps performance stable.
Reverse proxy choices
Caddy is simple and auto-renews certificates. Traefik brings dynamic discovery if you like labels. Nginx is lean and predictable with powerful caching if you need it. All will work if headers and timeouts are correct.
External binary data
Enterprise deployments can push binaries to object storage. For community builds stick to memory default in queue mode or filesystem in single-node mode. Avoid storing large blobs in the database unless you accept bigger backups and slower restores.
FAQ
How do I size a VPS for n8n?
Begin with 2 vCPU and 4 GB RAM for light workloads. If you see long queue times or the editor feels sluggish under load move to 4 vCPU and 8 GB RAM. Keep fast NVMe storage and enough free space for logs, database growth and snapshots.
How do I deploy n8n with Docker on a clean server?
Install Docker and Docker Compose. Create the compose file in this guide with a .env
file. Point DNS to the server then let Caddy handle certificates. Start the stack with docker compose up -d
and visit your HTTPS domain. Or deploy a LumaDock n8n VPS that comes with everything pre-installed.
How do I choose between SQLite and PostgreSQL?
SQLite keeps things simple for tests or tiny internal tools. PostgreSQL is better for production since it handles concurrency and larger execution logs safely. If you start on SQLite you can migrate to Postgres later.
How do I enable queue mode with Redis and workers?
Add a Redis service. Set EXECUTIONS_MODE=queue
. Start at least one worker with the n8n worker
command. Keep the editor as a single process and scale workers with --scale worker=N
. All services must use the same PostgreSQL database.
How do I fix wrong webhook URLs behind a reverse proxy?
Set N8N_HOST
, N8N_PROTOCOL
and WEBHOOK_URL
. Forward X-Forwarded-*
headers at the last proxy hop and set N8N_PROXY_HOPS=1
. Restart the containers after changes.
How do I store large files without bloating the database?
On single-node set N8N_DEFAULT_BINARY_DATA_MODE=filesystem
and mount a volume for the path. In queue mode keep the default binary mode since filesystem mode is not supported.
How do I back up and restore safely?
Back up Postgres with pg_dump
, persist the .n8n
directory and persist the binary data path if you use filesystem mode in single-node. Store backups off-box with encryption then rehearse a restore on a staging VPS so the steps are muscle memory.
How do I monitor a production instance?
Track CPU, RAM, disk, Postgres connections, Redis ops and queue depth. Use Uptime Kuma for external checks and Prometheus with Grafana for metrics and dashboards. Alert on container restarts and rising queue wait time.
How do I update n8n without drama?
Test the new image in staging. In production drain workers then roll them one by one and roll the editor last. Keep the old tag for rollback and watch metrics after the change.
How do I stay within the license?
Self-host for your internal business use or personal projects. Do not resell n8n as a hosted product without a commercial agreement. If your plan includes resale talk to the vendor first.
If you want to launch on a preconfigured platform: LumaDock gives you a clean VPS with Docker, Docker Compose and Caddy ready to go. You get 24/7 support from our in-house team, triple-replicated NVMe, unmetered bandwidth, DDoS protection, firewall control, IPv4 and daily snapshot options. Try it risk-free with a 30-day refund period!