How to self-host n8n on an EU VPS with Docker, PostgreSQL and HTTPS
n8n Cloud bills per workflow execution. Self-hosted n8n has no execution limit, and your workflow data stays on a server you control in the EU.
What size of VPS you need
| Workload | VPS |
|---|---|
| Personal automations, up to ~50 workflows | 2 vCores, 4 GB RAM |
| Business workflows, AI agents, heavy webhooks | 4 vCores, 8 GB RAM |
Our smallest plan, 2 vCores, 4 GB RAM and 100 GB disk for €4.54 a month, runs n8n and PostgreSQL comfortably. CPU is uncapped, so long workflow runs are not throttled.
1. Prepare the server
Create a Debian 12 or Ubuntu 24.04 VM, then point a DNS record such as n8n.example.com at its IP.
apt update && apt -y upgrade
curl -fsSL https://get.docker.com | sh
This installs Docker Engine with the Compose plugin from Docker's own repository.
On a Euronodes VM, add our Docker Hub mirror to skip Hub's rate limits: Docker Hub mirror.
2. Docker Compose file
Create /opt/n8n/docker-compose.yml:
services:
postgres:
image: postgres:16
restart: unless-stopped
environment:
POSTGRES_USER: n8n
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: n8n
volumes:
- pg_data:/var/lib/postgresql/data
n8n:
image: docker.n8n.io/n8nio/n8n
restart: unless-stopped
depends_on:
- postgres
environment:
DB_TYPE: postgresdb
DB_POSTGRESDB_HOST: postgres
DB_POSTGRESDB_DATABASE: n8n
DB_POSTGRESDB_USER: n8n
DB_POSTGRESDB_PASSWORD: ${POSTGRES_PASSWORD}
N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}
N8N_HOST: n8n.example.com
N8N_PROTOCOL: https
WEBHOOK_URL: https://n8n.example.com/
GENERIC_TIMEZONE: Europe/Lisbon
volumes:
- n8n_data:/home/node/.n8n
caddy:
image: caddy:2
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
volumes:
pg_data:
n8n_data:
caddy_data:
Create /opt/n8n/.env with two random secrets:
cd /opt/n8n
echo "POSTGRES_PASSWORD=$(openssl rand -hex 24)" > .env
echo "N8N_ENCRYPTION_KEY=$(openssl rand -hex 32)" >> .env
chmod 600 .env
Keep a copy of N8N_ENCRYPTION_KEY somewhere safe.
Without it, a restored database cannot decrypt your saved credentials.
3. HTTPS with Caddy
Create /opt/n8n/Caddyfile:
n8n.example.com {
reverse_proxy n8n:5678
}
Caddy gets and renews the Let's Encrypt certificate by itself. Port 5678 is never exposed to the internet, only 80 and 443 are.
4. Start it
docker compose up -d
docker compose logs -f n8n
Open https://n8n.example.com and create the owner account.
5. Firewall
Allow only SSH, HTTP and HTTPS:
apt -y install ufw
ufw allow 22/tcp && ufw allow 80/tcp && ufw allow 443/tcp
ufw enable
Use SSH keys and disable password login. Our VM security guide covers the rest.
6. Off-site backups
Back up the database, not the container:
docker compose exec -T postgres pg_dump -U n8n n8n | gzip > /root/n8n-$(date +%F).sql.gz
Push the dumps off the VM with restic or rclone, from a daily cron job. A backup that lives on the same server is not a backup: restic backup guide. On a Euronodes VPS you can add S3 backup storage to your account for exactly this.
Updating n8n
cd /opt/n8n
docker compose pull && docker compose up -d
Take a database dump first, and read the n8n release notes before a major version.
Why run it in the EU
Your workflows touch customer emails, CRM records and API keys. On a VPS in Lisbon or Prague, run by an EU company under a GDPR data processing agreement, that data stays in the EU.
Plans start at €4.54 a month, billed hourly: VPS in Portugal.