In this guide, you’ll learn how to deploy n8n on a VPS from Unihost (UNH series) with PostgreSQL, running behind the Traefik reverse proxy.
The setup will automatically issue and renew HTTPS certificates using Let’s Encrypt.
Everything will be managed from a single directory, and the whole deployment will run with just one command.
Why this guide skips Docker installation
Our Unihost VPS (UNH model) already includes Docker, so there’s no need to install it separately.
When ordering a VPS, you can also select an operating system image with Docker pre-installed — simply choose the appropriate OS in the configurator, and your server will be ready for immediate use.

Prerequisites
DNS: Create an A-record like:
n8n.<your_domain> → <your server’s public IP>
Ports: Make sure ports 80/tcp and 443/tcp are open on your server.
Create the directory and the .env file
mkdir -p ~/n8n-stack && cd ~/n8n-stack
nano .env
Paste the following content into the .env file, and make sure to replace DOMAIN, ACME_EMAIL, and all passwords with your own secure values:
# === Domain and Let's Encrypt ===
DOMAIN=yourdomain # replace with your real domain
ACME_EMAIL=admin@yourdomain # valid email for Let's Encrypt
# === n8n UI access (built-in basic auth) ===
N8N_BASIC_AUTH_ACTIVE=true
N8N_BASIC_AUTH_USER=admin
N8N_BASIC_AUTH_PASSWORD=ChangeMe_Soon
# === n8n URL and protocols ===
N8N_HOST=${DOMAIN}
N8N_PORT=5678
N8N_PROTOCOL=https
WEBHOOK_URL=https://${DOMAIN}
N8N_SECURE_COOKIE=true
N8N_RUNNERS_ENABLED=true
# === PostgreSQL database ===
POSTGRES_USER=n8n
POSTGRES_PASSWORD=n8npass
POSTGRES_DB=n8n
DB_TYPE=postgresdb
DB_POSTGRESDB_HOST=postgres
DB_POSTGRESDB_PORT=5432
DB_POSTGRESDB_DATABASE=${POSTGRES_DB}
DB_POSTGRESDB_USER=${POSTGRES_USER}
DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}
Notes:
- ACME_EMAIL is a valid email address used to register an account with Let’s Encrypt and to receive important notifications.
- N8N_BASIC_AUTH_* enables basic authentication for the n8n web interface.
- WEBHOOK_URL must point to your public HTTPS domain (do not include a trailing slash).
Create docker-compose.yml
nano docker-compose.yml
Paste the following content:
networks:
proxy:
name: proxy
internal:
volumes:
traefik_letsencrypt:
n8n_data:
pg_data:
services:
traefik:
image: traefik:v3.0
container_name: traefik
restart: unless-stopped
command:
- --api.dashboard=true
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --entrypoints.web.http.redirections.entryPoint.to=websecure
- --entrypoints.web.http.redirections.entryPoint.scheme=https
- --providers.docker=true
- --providers.docker.exposedbydefault=false
- --certificatesresolvers.lehttp.acme.httpchallenge=true
- --certificatesresolvers.lehttp.acme.httpchallenge.entrypoint=web
- --certificatesresolvers.lehttp.acme.email=${ACME_EMAIL}
- --certificatesresolvers.lehttp.acme.storage=/letsencrypt/acme.json
ports:
- "80:80"
- "443:443"
volumes:
- traefik_letsencrypt:/letsencrypt
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- proxy
postgres:
image: postgres:16
container_name: n8n-postgres
restart: unless-stopped
env_file: .env
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
volumes:
- pg_data:/var/lib/postgresql/data
networks:
- internal
n8n:
image: n8nio/n8n:latest
container_name: n8n
restart: unless-stopped
env_file: .env
depends_on:
- postgres
volumes:
- n8n_data:/home/node/.n8n
networks:
- internal
- proxy
labels:
- traefik.enable=true
- traefik.docker.network=proxy
- traefik.http.routers.n8n.rule=Host(`${DOMAIN}`)
- traefik.http.routers.n8n.entrypoints=websecure
- traefik.http.routers.n8n.tls=true
- traefik.http.routers.n8n.tls.certresolver=lehttp
- traefik.http.services.n8n.loadbalancer.server.port=5678
Why this setup works well:
- A fixed network name proxy is defined so that Traefik and n8n can reliably communicate with each other.
- env_file: .env is used for both postgres and n8n containers — this ensures all environment variables from the .env file are injected into the containers.
- Port 5678 of the n8n container is not exposed to the outside — access is only allowed through Traefik over HTTPS.
- The label traefik.docker.network=proxy explicitly tells Traefik which network to use when connecting to n8n, which is necessary if the container is attached to multiple networks.
Step 3. Launch
docker compose up -d
Wait about 10–60 seconds: n8n will run the database migrations, and Traefik, on the first access to the domain, will request a Let’s Encrypt certificate. Within a couple of minutes, your certificate should be active.
If the certificate is still inactive after a few minutes, your browser may have cached the page. Try opening n8n in Incognito/Private mode.
Quick Summary
After completing these steps, you’ll have a fully functional n8n instance with a PostgreSQL database and automatic HTTPS via Traefik.
This setup is convenient because:
- Everything is managed with a single command: docker compose up -d
- Traefik automatically issues and renews Let’s Encrypt certificates.
- The database is isolated and accessible only to the n8n container
- You can easily add more services behind Traefik on different subdomains