Skip to content

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.