How to Deploy Notifuse on a VPS with Docker and Traefik

Learn how to deploy Notifuse on Ubuntu or Debian VPS using Docker, PostgreSQL, Traefik, domain routing, SSL, and persistent volumes

How to Deploy Notifuse on a VPS with Docker and Traefik
Notifuse on a VPS with Docker and Traefik

If you want to self-host Notifuse on Ubuntu or Debian with your own domain, the cleanest setup is Docker Compose, PostgreSQL, persistent volumes, and Traefik for HTTPS routing. This gives you a production-style deployment that works on AWS, GCP, Vultr, Hetzner, DigitalOcean, or almost any VPS.

The short answer: install Docker on your VPS, create a separate Traefik reverse proxy stack, deploy Notifuse in its own folder with PostgreSQL and persistent storage, then connect both stacks through a shared Docker network. Notifuse provides a setup wizard on first launch, but production deployments should keep sensitive values like SECRET_KEY, database credentials, and SMTP credentials in environment variables. (Notifuse Documentation)

Why This Problem Exists

Notifuse is simple to run, but production hosting needs more than a single docker run command. The application needs a PostgreSQL database, a public API endpoint, SMTP configuration, and stable storage so your workspaces and email settings survive container restarts. The official Notifuse documentation recommends Docker Compose for testing and standalone Docker with your own PostgreSQL database for production-style deployments. (Notifuse Documentation)

The most common mistake is exposing the app directly on a random port like 8081 and then trying to add SSL later. That works for testing, but it becomes messy when you want https://emails.yourdomain.com, multiple apps on the same VPS, automatic Let’s Encrypt certificates, and clean routing.

Traefik solves that part. It watches Docker containers and uses labels to create routing rules, which means you can map a domain to a container without manually editing Nginx config every time. Traefik’s Docker integration is designed around labels and controlled exposure of services. (doc.traefik.io)

The Solution — VPS Notifuse with Docker, PostgreSQL and Traefik

This setup uses two folders. One folder runs Traefik globally for your server. Another folder runs Notifuse and PostgreSQL. Both connect through one shared Docker network called traefik_proxy.

The final structure looks like this:

/opt/traefik
  docker-compose.yml
  letsencrypt/acme.json

/opt/notifuse
  docker-compose.yml
  .env
  data/

Step 1 is to install Docker on Ubuntu or Debian. Docker’s official documentation supports Docker Engine installation through the apt repository on both Debian and Ubuntu, and Debian support includes Bookworm 12 and Bullseye 11. (Docker Documentation)

sudo apt update
sudo apt install -y ca-certificates curl gnupg

For Ubuntu:

sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

For Debian:

sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Then install Docker:

sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

sudo systemctl enable docker
sudo systemctl start docker

Now create the shared network:

docker network create traefik_proxy

Set Up Traefik for Domain and SSL

Traefik should run separately because you can reuse it later for more apps like n8n, Listmonk, Ghost, Uptime Kuma, or internal dashboards.

Create the folder:

sudo mkdir -p /opt/traefik/letsencrypt
cd /opt/traefik
sudo touch letsencrypt/acme.json
sudo chmod 600 letsencrypt/acme.json

Create the Traefik compose file:

sudo nano docker-compose.yml

Paste this:

services:
  traefik:
    image: traefik:v3.0
    container_name: traefik
    restart: unless-stopped
    command:
      - "--api.dashboard=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.letsencrypt.acme.email=admin@yourdomain.com"
      - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
      - "--certificatesresolvers.letsencrypt.acme.httpchallenge=true"
      - "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
    ports:
      - "80:80"
      - "443:443"
    networks:
      - traefik_proxy
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./letsencrypt:/letsencrypt

networks:
  traefik_proxy:
    external: true

Replace [email protected] with your real email.

Start Traefik:

docker compose up -d

Before moving ahead, point your DNS record to the VPS:

Type: A
Name: emails
Value: YOUR_SERVER_IP

Your final Notifuse URL will be:

https://emails.yourdomain.com

Deploy Notifuse in a Separate Folder

Now create a separate folder for Notifuse:

sudo mkdir -p /opt/notifuse/data
cd /opt/notifuse

Generate a strong secret key:

openssl rand -base64 32

Notifuse warns that SECRET_KEY must never be changed after initial setup because it encrypts workspace integration secrets such as SMTP passwords and provider API keys. Changing it later can permanently break encrypted credentials. (Notifuse Documentation)

Create your .env file:

sudo nano .env

Use this:

SERVER_PORT=8080
SERVER_HOST=0.0.0.0
ENVIRONMENT=production

DB_HOST=postgres
DB_PORT=5432
DB_USER=postgres
DB_PASSWORD="change-this-strong-password"
DB_PREFIX=notifuse
DB_NAME=notifuse_system
DB_SSLMODE=disable

SECRET_KEY="paste-your-generated-secret-key-here"

[email protected]
API_ENDPOINT=https://emails.yourdomain.com

SMTP_HOST=smtp.yourprovider.com
SMTP_PORT=587
[email protected]
SMTP_PASSWORD="your-smtp-password"
[email protected]
SMTP_FROM_NAME=Your Company Name

If your password contains #, keep it inside quotes. Notifuse specifically documents this because .env files can truncate unquoted values after #. (Notifuse Documentation)

Now create the Notifuse Docker Compose file:

sudo nano docker-compose.yml

Paste this production-friendly version:

services:
  api:
    image: notifuse/notifuse:latest
    container_name: notifuse_api
    restart: unless-stopped
    environment:
      - SERVER_PORT=${SERVER_PORT:-8080}
      - SERVER_HOST=${SERVER_HOST:-0.0.0.0}
      - ENVIRONMENT=${ENVIRONMENT:-production}

      - DB_HOST=${DB_HOST:-postgres}
      - DB_PORT=${DB_PORT:-5432}
      - DB_USER=${DB_USER:-postgres}
      - DB_PASSWORD=${DB_PASSWORD:-postgres}
      - DB_PREFIX=${DB_PREFIX:-notifuse}
      - DB_NAME=${DB_NAME:-notifuse_system}
      - DB_SSLMODE=${DB_SSLMODE:-disable}

      - SECRET_KEY=${SECRET_KEY}

      - ROOT_EMAIL=${ROOT_EMAIL}
      - API_ENDPOINT=${API_ENDPOINT}

      - SMTP_HOST=${SMTP_HOST}
      - SMTP_PORT=${SMTP_PORT}
      - SMTP_USERNAME=${SMTP_USERNAME}
      - SMTP_PASSWORD=${SMTP_PASSWORD}
      - SMTP_FROM_EMAIL=${SMTP_FROM_EMAIL}
      - SMTP_FROM_NAME=${SMTP_FROM_NAME}

    depends_on:
      postgres:
        condition: service_healthy

    volumes:
      - ./data:/app/data

    networks:
      - notifuse-network
      - traefik_proxy

    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.notifuse.rule=Host(`emails.yourdomain.com`)"
      - "traefik.http.routers.notifuse.entrypoints=websecure"
      - "traefik.http.routers.notifuse.tls.certresolver=letsencrypt"
      - "traefik.http.services.notifuse.loadbalancer.server.port=8080"

      - "traefik.http.routers.notifuse-http.rule=Host(`emails.yourdomain.com`)"
      - "traefik.http.routers.notifuse-http.entrypoints=web"
      - "traefik.http.routers.notifuse-http.middlewares=notifuse-https"
      - "traefik.http.middlewares.notifuse-https.redirectscheme.scheme=https"

    healthcheck:
      test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/healthz"]
      interval: 10s
      timeout: 5s
      retries: 3
      start_period: 10s

  postgres:
    image: postgres:17-alpine
    container_name: notifuse_postgres
    restart: unless-stopped
    environment:
      - POSTGRES_USER=${DB_USER:-postgres}
      - POSTGRES_PASSWORD=${DB_PASSWORD:-postgres}
      - POSTGRES_DB=${DB_NAME:-notifuse_system}
    volumes:
      - postgres-data:/var/lib/postgresql/data
    networks:
      - notifuse-network
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-postgres}"]
      interval: 5s
      timeout: 5s
      retries: 5

volumes:
  postgres-data:
    driver: local

networks:
  notifuse-network:
    driver: bridge
  traefik_proxy:
    external: true

Change emails.yourdomain.com to your real domain in both Traefik labels.

Start Notifuse:

docker compose up -d

Check logs:

docker compose logs -f api

Visit:

https://emails.yourdomain.com

You should see the Notifuse Setup Wizard. The wizard lets you configure root admin email, API endpoint, and SMTP settings through the web interface, although environment variables always take priority when present. (Notifuse Documentation)

Why This Setup Works Better Than a Basic Docker Run

This setup is better because it separates routing, application logic, database storage, and secrets. A single docker run command is fine for testing, but it becomes harder to maintain when SSL, domain routing, backup, and updates are involved.

SetupBest ForSSLDatabase PersistenceScaling
Docker Compose with embedded PostgreSQLTesting and small demosManual unless proxiedYes, if volume configuredBasic
Standalone Docker onlyQuick production testManual unless proxiedDepends on external DBMedium
Docker Compose with Traefik and PostgreSQLVPS production setupAutomatic Let’s EncryptYesStrong
KubernetesLarge infrastructure teamsIngress-basedRequires storage classAdvanced

For most VPS deployments, Docker Compose plus Traefik is the best balance. It is simple enough to maintain but structured enough for real production use.

Common Mistakes and How to Avoid Them

The most common mistake we see is exposing PostgreSQL publicly. In your compose file, avoid this unless you absolutely need remote database access:

ports:
  - "5433:5432"

For a normal single-server deployment, PostgreSQL should stay private inside the Docker network. Your Notifuse API can talk to it internally using DB_HOST=postgres.

Another mistake is changing SECRET_KEY after setup. Don’t do that. Treat it like a database encryption master key. Back it up somewhere secure.

A third mistake is mixing multiple reverse proxies. If Traefik is already listening on ports 80 and 443, don’t install Nginx or Caddy on the same ports unless you know exactly what you’re doing.

The final mistake is forgetting DNS. Traefik can only issue SSL certificates when your domain points to the server and ports 80 and 443 are open.

Real-World Example

A clean Notifuse VPS deployment usually takes 30–45 minutes when DNS is ready. In one Hitori Tech-style setup, the app ran on a Hetzner VPS with Traefik already handling Ghost, Listmonk, and n8n. Adding Notifuse only required a new folder, a new compose file, one shared Docker network, and a domain label.

The result was simple: https://emails.clientdomain.com routed to Notifuse, PostgreSQL stayed private, SSL renewed automatically, and future updates only required:

cd /opt/notifuse
docker compose pull
docker compose up -d

That is the real benefit of this structure. You can add more apps later without rebuilding your server from scratch.

Frequently Asked Questions

What is the best way to deploy Notifuse on a VPS?

The best VPS setup is Docker Compose with PostgreSQL, persistent volumes, and Traefik for HTTPS domain routing. This keeps the database private, gives you automatic SSL, and makes updates easier.

Can I install Notifuse on Ubuntu and Debian?

Yes, Notifuse can run on both Ubuntu and Debian as long as Docker Engine and Docker Compose are installed. Docker officially supports installation through apt repositories for both distributions. (Docker Documentation)

Do I need Traefik for Notifuse?

You don’t strictly need Traefik, but it is highly useful when hosting Notifuse on a real domain. Traefik handles HTTPS, redirects HTTP to HTTPS, and routes traffic from your domain to the Notifuse container.

Should PostgreSQL be exposed with a public port?

No, PostgreSQL should usually stay private inside the Docker network. Exposing database ports publicly increases risk and is unnecessary when Notifuse and PostgreSQL run on the same VPS.

What happens if I change the Notifuse SECRET_KEY?

Changing SECRET_KEY after setup can permanently break encrypted workspace secrets, including SMTP passwords and email provider API keys. Generate it once, store it safely, and do not rotate it casually.

Can I use the Notifuse Setup Wizard instead of environment variables?

Yes, the Setup Wizard is useful for first-time setup and non-sensitive configuration. For production, sensitive values like database credentials, SMTP passwords, and SECRET_KEY should be managed with environment variables.

If you’re already self-hosting tools like n8n, Ghost, Listmonk, or internal dashboards, this Notifuse setup fits naturally into the same VPS architecture. Keep Traefik as your shared entry point, keep every app in its own folder, and keep databases private unless there is a clear reason to expose them.

For help building production-ready Docker, Traefik, and automation stacks, explore Hitori Tech’s DevOps services at https://hitoritech.com/digital-agency or contact the team at https://hitoritech.com/contact.

Himanshu Verma

Written by

Himanshu Verma

Himanshu is a full-stack developer and SaaS builder behind VerifiSaaS. He shares practical insights on email verification, deliverability, and growth systems to help businesses scale smarter