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