Self-host n8n on a VPS
Set up your own n8n instance with SSL and a custom domain for ~€5/month.
Overview
This guide walks you through setting up your own n8n instance on a VPS (Virtual Private Server). Self-hosting gives you unlimited workflow executions for a fraction of the cost of cloud plans.
If you build in Make, skip this page - Make is hosted and needs no setup.
n8n Cloud costs $24/month for just 2,500 executions. Self-hosting on Hetzner gives you unlimited executions for ~€5/month. Perfect for learning, development, and production workloads.
Prerequisites
Before starting, make sure you have:
- A Hetzner account - Sign up at hetzner.com/cloud
- A domain you control - For SSL certificates (optional but recommended)
- Terminal access - macOS Terminal, Windows PowerShell, or Linux terminal
Part 1: create the server
Step 1: create a Hetzner account
- Go to hetzner.com/cloud
- Sign up and add a payment method (~€20 initial charge becomes credit)
Step 2: create a new server
- Click "Add Server"
- Configure the following:
| Setting | Value |
|---|---|
| Location | Nuremberg (or closest to you) |
| Image | Ubuntu 24.04 |
| Type | CX22 or CX23 (Shared, ~€4-5/month) |
| Networking | IPv4 + IPv6 |
Step 3: set up an SSH key
Before creating the server, add your SSH key for secure access.
Check if you have an SSH key:
cat ~/.ssh/id_rsa.pubIf no key exists, generate one:
ssh-keygen -t rsa -b 4096
# Press Enter through all promptsCopy your public key:
cat ~/.ssh/id_rsa.pubIn Hetzner:
- Click "+ Add SSH key"
- Paste your public key
- Name it (e.g., "MacBook")
Step 4: finalize server creation
- Volumes: Skip
- Firewalls: Skip
- Backups: Skip (optional, adds 20% cost)
- Name:
n8n-dev(or whatever you prefer)
Click "Create & Buy now" and wait for the green status dot.
Part 2: install Docker
Step 1: connect to your server
ssh root@YOUR_SERVER_IPReplace YOUR_SERVER_IP with the IPv4 address from your Hetzner dashboard. Type yes when asked about the fingerprint.
Step 2: update the system and install Docker
apt update && apt upgrade -y && apt install -y docker.io docker-compose-v2 && systemctl enable docker && systemctl start dockerWait until the installation completes.
Part 3: basic n8n setup (no SSL)
Use this for quick testing without a domain. Skip to Part 4 if you have a domain ready.
Step 1: create a project directory
mkdir -p /opt/n8n && cd /opt/n8nStep 2: create the Docker Compose file
nano docker-compose.ymlPaste this configuration:
services:
n8n:
image: n8nio/n8n
restart: always
ports:
- "5678:5678"
environment:
- N8N_HOST=localhost
- N8N_PORT=5678
- N8N_PROTOCOL=http
- WEBHOOK_URL=http://localhost:5678/
- N8N_SECURE_COOKIE=false
volumes:
- n8n_data:/home/node/.n8n
volumes:
n8n_data:Save: Ctrl + X, then Y, then Enter
Step 3: start n8n
docker compose up -dStep 4: access n8n
Open in your browser: http://YOUR_SERVER_IP:5678
Part 4: add a custom domain with SSL
SSL is required for secure webhooks and is strongly recommended for any serious use.
Step 1: add a DNS record
In your domain provider (Hostinger, Cloudflare, Namecheap, etc.):
- Go to DNS settings for your domain
- Add an A Record:
| Field | Value |
|---|---|
| Name/Host | n8n |
| Value/Points to | Your server's IP address |
| TTL | 3600 |
This creates n8n.yourdomain.com. Wait a few minutes for DNS propagation.
Step 2: stop the current n8n (if running)
cd /opt/n8n
docker compose downStep 3: update the config with SSL
rm docker-compose.yml && nano docker-compose.ymlPaste this configuration (replace YOUR_DOMAIN and YOUR_EMAIL):
services:
traefik:
image: traefik:v3.0
restart: always
command:
- "--api=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.letsencrypt.acme.tlschallenge=true"
- "--certificatesresolvers.letsencrypt.acme.email=YOUR_EMAIL"
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
ports:
- "80:80"
- "443:443"
volumes:
- traefik_data:/letsencrypt
- /var/run/docker.sock:/var/run/docker.sock:ro
n8n:
image: n8nio/n8n
restart: always
environment:
- N8N_HOST=YOUR_DOMAIN
- N8N_PORT=5678
- N8N_PROTOCOL=https
- WEBHOOK_URL=https://YOUR_DOMAIN/
- N8N_SECURE_COOKIE=true
volumes:
- n8n_data:/home/node/.n8n
labels:
- "traefik.enable=true"
- "traefik.http.routers.n8n.rule=Host(`YOUR_DOMAIN`)"
- "traefik.http.routers.n8n.entrypoints=websecure"
- "traefik.http.routers.n8n.tls.certresolver=letsencrypt"
- "traefik.http.services.n8n.loadbalancer.server.port=5678"
volumes:
traefik_data:
n8n_data:YOUR_EMAIL→ your actual email (for SSL certificate notifications)YOUR_DOMAIN→ e.g.,n8n.yourdomain.com(appears 4 times)
Step 4: start with SSL
docker compose up -dWait 30 seconds for SSL certificate provisioning.
Step 5: access n8n
Open in your browser: https://n8n.yourdomain.com
You should see a green padlock (secure connection).
Part 5: generate an API key
To connect n8n with external tools or MCP servers, generate an API key:
- In n8n, click your profile icon (bottom left)
- Go to Settings
- Click API or API Keys
- Click Create API Key
- Name it (e.g., "Claude MCP" or "External Access")
- Copy and save the key securely
Store your API key securely. It grants full access to your n8n instance.
Useful commands
Check if n8n is running
docker psView logs
cd /opt/n8n && docker compose logs -fRestart n8n
cd /opt/n8n && docker compose restartStop n8n
cd /opt/n8n && docker compose downStart n8n
cd /opt/n8n && docker compose up -dUpdate n8n to latest version
cd /opt/n8n
docker compose down
docker pull n8nio/n8n
docker compose up -dSSH into server
ssh root@YOUR_SERVER_IPTroubleshooting
Can't access n8n in browser
- Check if container is running:
docker ps - Check logs:
docker compose logs - Verify firewall allows ports 80, 443, 5678
SSL not working
- Ensure DNS is pointing to correct IP:
ping n8n.yourdomain.com - Wait a few minutes for DNS propagation
- Check Traefik logs:
docker compose logs traefik
n8n showing old data after restart
- Data persists in Docker volumes - this is normal behavior
- To reset completely:
docker volume rm n8n_n8n_data
Cost summary
| Item | Cost |
|---|---|
| Hetzner CX22/CX23 | ~€4-5/month |
| Domain (if new) | ~€10/year |
| SSL Certificate | Free (Let's Encrypt) |
| Total | ~€5/month |
Comparison with n8n Cloud
Your self-hosted n8n instance is now running with SSL. You can create workflows, set up webhooks, and connect to Nodox briefs using your custom domain.