How to Self-Host n8n with Docker Compose (2026 Guide)
To self-host n8n with Docker Compose you need one docker-compose.yml with the n8nio/n8n image, a named volume mounted at /home/node/.n8n, and the N8N_HOST, WEBHOOK_URL and GENERIC_TIMEZONE environment variables set — then docker compose up -d. The default setup stores everything in SQLite and speaks plain HTTP on port 5678, so this guide also covers the four things that bare file leaves out: PostgreSQL, restarting after a reboot, HTTPS, and doing it all without Traefik.
n8n is a popular open-source automation tool – like Zapier, but self-hosted. Here's how to run it on your own VPS using Docker Compose, and expose it securely over HTTPS using Caddy as the ingress proxy.
If you want a broader primer, check out How to Self-Host a Docker Compose App. But you don't need to read it first – this guide is self-contained.
🗓️ Last updated: August 2026. Tested with the latest
n8nio/n8nimage on Ubuntu 24.04.
1. Install Docker on your VPS
Update the system and install Docker + Compose plugin:
apt update && apt upgrade -y
apt-get install ca-certificates curl -y
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" \
| tee /etc/apt/sources.list.d/docker.list > /dev/null
apt-get update
apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin -y
2. Write a Docker Compose file
Create a new directory for n8n and add docker-compose.yml:
services:
n8n:
image: n8nio/n8n:latest
restart: always
ports:
- "127.0.0.1:5678:5678"
environment:
- N8N_HOST=n8n.example.com
- N8N_PORT=5678
- N8N_PROTOCOL=https
volumes:
- n8n_data:/home/node/.n8n
volumes:
n8n_data:
💡 Note: This guide assumes you already have a domain (like
n8n.example.com) pointing to your VPS's IP address. If not, set that up with your DNS provider before continuing.
Notice we bind to 127.0.0.1:5678 – so it's only accessible locally. Caddy will handle public access.
Start it:
docker compose up -d
n8n Docker Compose with PostgreSQL instead of SQLite
By default n8n stores everything in a SQLite file inside the volume. That's fine for personal use. For anything with real workflow volume, switch to PostgreSQL – it handles concurrent writes far better and is easier to back up.
Add a Postgres service and point n8n at it:
services:
n8n:
image: n8nio/n8n:latest
restart: always
ports:
- "127.0.0.1:5678:5678"
environment:
- N8N_HOST=n8n.example.com
- N8N_PORT=5678
- N8N_PROTOCOL=https
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=postgres
- DB_POSTGRESDB_DATABASE=n8n
- DB_POSTGRESDB_USER=n8n
- DB_POSTGRESDB_PASSWORD=change-me
volumes:
- n8n_data:/home/node/.n8n
depends_on:
- postgres
postgres:
image: postgres:16
restart: always
environment:
- POSTGRES_DB=n8n
- POSTGRES_USER=n8n
- POSTGRES_PASSWORD=change-me
volumes:
- n8n_pg:/var/lib/postgresql/data
volumes:
n8n_data:
n8n_pg:
💡 Set a real password and keep the
n8n_pgvolume – that's where your workflows and credentials now live. Back it up withdocker compose exec postgres pg_dump -U n8n n8n > backup.sql.
3. Make it survive reboots
Create a systemd service:
# /etc/systemd/system/n8n.service
[Unit]
Description=n8n workflow automation (Docker Compose)
After=network.target
[Service]
Type=oneshot
WorkingDirectory=/root/n8n
ExecStart=/usr/bin/docker compose up -d
ExecStop=/usr/bin/docker compose down
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
Enable it:
systemctl enable n8n
systemctl start n8n
Now n8n restarts automatically after reboots.
4. Install and configure Caddy (n8n Docker Compose without Traefik)
Caddy is a modern reverse proxy with automatic HTTPS. Perfect for small setups.
If you're curious about how Caddy compares to Nginx, HAProxy, or Traefik, see The Reverse Proxy Showdown. For n8n, Caddy is the simplest choice.
Make sure your domain (e.g. n8n.example.com) already resolves to your VPS before you configure Caddy. Otherwise, Let's Encrypt won't be able to issue a certificate.
apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | tee /etc/apt/trusted.gpg.d/caddy-stable.asc
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list
apt update
apt install caddy -y
Edit the Caddyfile:
nano /etc/caddy/Caddyfile
Add:
n8n.example.com {
reverse_proxy localhost:5678
}
Reload Caddy:
systemctl reload caddy
That's it – Caddy requests and renews Let's Encrypt certificates automatically.
5. Secure access
- Use strong credentials when creating first user.
- Keep the
docker-compose.ymlvolume so your workflows persist. - Optionally, restrict access to your IP range using Caddy if it's just for personal use.
Wrapping Up
You now have a self-hosted n8n instance:
- Running in Docker Compose
- Restarting automatically after reboots
- Exposed via Caddy with HTTPS
If you want to avoid managing servers altogether, platforms like Hostim.dev let you paste a Compose file and get HTTPS, metrics, and persistence without touching SSH – on a flat monthly price, not metered per-minute billing.
But if you prefer DIY – this setup will take you far.
Frequently asked questions
How do I self-host n8n with Docker Compose?
Create a docker-compose.yml with the n8nio/n8n image, publish port 5678, mount a named volume at /home/node/.n8n so workflows and credentials persist, set N8N_HOST, WEBHOOK_URL and GENERIC_TIMEZONE, then run 'docker compose up -d'. Put a reverse proxy in front of it for HTTPS before you expose it to the internet.
Can I run n8n with Docker Compose without Traefik?
Yes. Traefik is only the reverse proxy in n8n's own example file, not a requirement. Caddy is simpler: two lines in a Caddyfile give you automatic Let's Encrypt certificates in front of n8n on port 5678. Nginx or HAProxy work too, and on a private network you can skip the proxy entirely.
Should n8n use SQLite or PostgreSQL?
SQLite is the default and is fine for a personal instance. Switch to PostgreSQL if several workflows run concurrently or you plan to back up and restore the instance — set DB_TYPE=postgresdb plus the DB_POSTGRESDB_* variables and add a postgres service to the same Compose file.
Where does n8n store workflows in Docker?
In /home/node/.n8n inside the container. Mount a named volume there or every workflow, credential and encryption key disappears when the container is recreated. With PostgreSQL configured, workflow data moves to the database but the encryption key still lives in that directory.
Why do n8n webhooks return the wrong URL?
Because WEBHOOK_URL still points at localhost or the container port. Set WEBHOOK_URL and N8N_HOST to the public HTTPS URL your reverse proxy serves, and set N8N_PROTOCOL to https, then recreate the container.
How do I make n8n restart after a server reboot?
Add 'restart: unless-stopped' to the n8n service and make sure Docker itself starts at boot with 'systemctl enable docker'. Compose restart policies only apply once the Docker daemon is running.
How much does self-hosting n8n cost?
n8n's community edition is free to run, so the cost is the server. A 2 GB VPS handles a personal instance; add PostgreSQL and busy workflows and you want 4 GB. Managed platforms that run the same container start around a few euros a month.