How to install n8n on a VPS
n8n connects APIs and services through visual workflows that you can operate on your own infrastructure. This guide runs n8n with PostgreSQL and Docker Compose, keeps the editor private behind HTTPS and covers the configuration needed for reliable webhooks.
Prerequisites
Use a clean Ubuntu 22.04 or 24.04 VPS with SSH, a public IP and at least 2 GB of RAM. Add memory when workflows execute code, process files or run concurrently. Create an A record such as n8n.example.com pointing to the VPS and reserve ports 80 and 443 for the reverse proxy.
You need Docker Engine, the Compose plugin, a backup destination and a generated encryption key. Do not paste API tokens into the Compose file. Store them in n8n credentials or a secret manager.
Step 1, Connecting to your server
Update the server and create a private application directory:
ssh root@SERVER_IP
apt update && apt upgrade -y
apt install -y ca-certificates curl
mkdir -p /opt/n8n
cd /opt/n8n
chmod 750 /opt/n8nCheck that ports 80 and 443 are free. If an old web server is already running, stop it only after identifying what depends on it. The n8n editor should not be exposed directly on a public port.
Step 2, Installing Docker and Docker Compose
Install Docker from its official Ubuntu instructions, then verify the Compose plugin:
docker --version
docker compose version
systemctl enable --now dockerUse a supported Docker package source and keep the engine updated. Do not add the Docker socket to an unrelated public-facing container.
Step 3, Running n8n with Docker Compose
Create .env with placeholders replaced by unique random values. The encryption key must remain stable for the lifetime of the installation:
POSTGRES_DB=n8n
POSTGRES_USER=n8n
POSTGRES_PASSWORD=REPLACE_WITH_A_RANDOM_VALUE
N8N_ENCRYPTION_KEY=REPLACE_WITH_A_LONG_RANDOM_VALUE
N8N_HOST=n8n.example.com
N8N_PROTOCOL=https
N8N_WEBHOOK_URL=https://n8n.example.com/
N8N_EDITOR_BASE_URL=https://n8n.example.com/
N8N_PROXY_HOPS=1Create compose.yaml:
services:
db:
image: postgres:16
restart: unless-stopped
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- db_data:/var/lib/postgresql/data
n8n:
image: docker.n8n.io/n8nio/n8n:latest
restart: unless-stopped
depends_on:
- db
environment:
DB_TYPE: postgresdb
DB_POSTGRESDB_HOST: db
DB_POSTGRESDB_DATABASE: ${POSTGRES_DB}
DB_POSTGRESDB_USER: ${POSTGRES_USER}
DB_POSTGRESDB_PASSWORD: ${POSTGRES_PASSWORD}
N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}
N8N_HOST: ${N8N_HOST}
N8N_PROTOCOL: ${N8N_PROTOCOL}
N8N_WEBHOOK_URL: ${N8N_WEBHOOK_URL}
N8N_EDITOR_BASE_URL: ${N8N_EDITOR_BASE_URL}
N8N_PROXY_HOPS: 1
ports:
- "127.0.0.1:5678:5678"
volumes:
- n8n_data:/home/node/.n8n
volumes:
db_data:
n8n_data:Start the project and inspect logs:
docker compose up -d
docker compose ps
docker compose logs --tail 100 n8nPin image versions after testing rather than relying on latest for production updates.
Step 4, Configuring the reverse proxy
Configure Caddy, Nginx or your platform proxy to forward n8n.example.com to 127.0.0.1:5678. The proxy must include these three headers for webhooks to function correctly:
X-Forwarded-Forโ preserves the original client IPX-Forwarded-Hostโ preserves the original hostnameX-Forwarded-Protoโ preserves the original protocol (HTTP/HTTPS)
Let the proxy handle HTTPS and keep 5678 bound to localhost and blocked by the firewall.
Test both the editor and a webhook endpoint. If a provider cannot reach the webhook, check DNS, certificate validity, proxy headers and the N8N_WEBHOOK_URL value before changing n8n workflow code.
Step 5, First access and initial setup
Open https://n8n.example.com and create the owner account. n8n enforces this since v0.200+, so the first user to register becomes the instance owner. Enable user management and limit invitations. Create one test credential, run a simple workflow and verify that its execution data is stored after a restart.
Review execution retention and disable verbose data storage where it is not needed. Credentials should be created inside n8n, not hard-coded in nodes or environment files that are copied around.
Maintenance
Back up the n8n_data volume (which contains the encryption key), PostgreSQL and the encryption key together. If the n8n_data volume is lost, all stored credentials become unrecoverable. A database backup without the encryption key cannot decrypt stored credentials. Upgrade one version at a time when the release notes require it, test workflows after each upgrade and keep a rollback copy.
Monitor queue time, memory, disk and failed executions. For larger workloads, move to the queue mode documented by n8n and provision a separate worker architecture instead of increasing a single container indefinitely.
Tools mentioned
n8n
โOpen-source workflow automation platform to connect apps and build automations visually.
Free self-hosted community edition with unlimited workflows. Cloud free tier with 5 active workflows.