Skip to content

How to install n8n on a VPS with Docker and Caddy

n8n is a workflow automation tool: you connect apps, APIs and AI models on a visual canvas and let the workflows run on triggers, schedules and webhooks. The self hosted version has no limit on executions, and your credentials stay on your own server. This guide installs n8n with Docker Compose behind the Caddy web server, which gets and renews a free HTTPS certificate for your domain automatically.

What you need

  • A VPS with Ubuntu 24.04. For personal automations we recommend VPS-2 (1 vCPU, 2 GB RAM, 32 GB NVMe). If a team uses n8n every day or your workflows process large files, take VPS-3 (2 vCPU, 4 GB RAM). All options are on the n8n hosting page. Billing is hourly, so you can move to a bigger plan later without a contract.
  • A domain or subdomain, for example n8n.example.com, with access to its DNS settings.
  • SSH access. See how to connect via SSH if this is new to you.

Step 1. Point the domain to the server

In your DNS provider create an A record:

TypeNameValue
An8nYOUR_SERVER_IP

Wait until the name resolves to your IP. You can check from your computer with ping n8n.example.com. Caddy can only get a certificate once DNS points to the server.

Step 2. Connect and install Docker

Log in and update the system:

bash
ssh root@YOUR_SERVER_IP
apt update && apt upgrade -y

Install Docker Engine and the Compose plugin with the official script from Docker:

bash
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh
docker compose version

Step 3. Open the firewall

Caddy needs ports 80 and 443. Port 80 is used for the certificate challenge and to redirect visitors to HTTPS. Allow SSH first, then the web ports:

bash
ufw allow OpenSSH
ufw allow 80/tcp
ufw allow 443
ufw enable

The rule for 443 without a protocol covers both TCP and UDP, so HTTP/3 works too. n8n itself listens on port 5678, but in this setup that port is only reachable inside the Docker network, never from the internet.

Step 4. Create the project files

Make a folder and an .env file with your settings:

bash
mkdir -p /opt/n8n
cd /opt/n8n
nano .env
bash
DOMAIN=n8n.example.com
GENERIC_TIMEZONE=Europe/Berlin

Replace the domain with yours and set your time zone. n8n uses it for schedule triggers.

Now create the Caddy configuration:

bash
nano Caddyfile
{$DOMAIN} {
    reverse_proxy n8n:5678
}

That is the whole config. Caddy sees a domain name, gets a certificate from Let's Encrypt, redirects HTTP to HTTPS and forwards requests to n8n. It sets the X-Forwarded-For, X-Forwarded-Host and X-Forwarded-Proto headers and proxies WebSocket connections by default, which the n8n editor needs.

Step 5. Write the Compose file

bash
nano compose.yaml
yaml
services:
  caddy:
    image: caddy:2
    restart: always
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"
    environment:
      - DOMAIN=${DOMAIN}
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data
      - caddy_config:/config

  n8n:
    image: n8nio/n8n
    restart: always
    environment:
      - N8N_HOST=${DOMAIN}
      - N8N_PORT=5678
      - N8N_PROTOCOL=https
      - N8N_WEBHOOK_URL=https://${DOMAIN}/
      - N8N_PROXY_HOPS=1
      - N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true
      - NODE_ENV=production
      - GENERIC_TIMEZONE=${GENERIC_TIMEZONE}
      - TZ=${GENERIC_TIMEZONE}
    volumes:
      - n8n_data:/home/node/.n8n

volumes:
  caddy_data:
  caddy_config:
  n8n_data:

What the n8n variables mean:

VariablePurpose
N8N_HOSTThe host name n8n runs on.
N8N_PROTOCOLhttps, because users reach n8n through Caddy over TLS.
N8N_WEBHOOK_URLThe public base URL for webhooks. n8n shows it in the editor and registers it with external services. Older guides call it WEBHOOK_URL, which still works but is deprecated since n8n 2.35.0.
N8N_PROXY_HOPSNumber of reverse proxies in front of n8n. With Caddy it is 1.
GENERIC_TIMEZONE, TZTime zone for schedules and for the container.

Step 6. Start n8n

bash
docker compose up -d
docker compose logs -f

Wait until the n8n log says the editor is accessible, then press Ctrl+C. Open https://n8n.example.com in your browser. The first visit asks you to set up the owner account. Do it right away, because until the owner exists anyone who opens the address can claim the instance.

Where your data lives

Two named volumes hold everything that must survive a restart:

  • n8n_data is mounted at /home/node/.n8n. It contains the SQLite database with workflows, executions and credentials, and the file with the encryption key that protects saved credentials.
  • caddy_data stores the TLS certificates and keys. Keep it, otherwise Caddy requests new certificates on every rebuild and can hit Let's Encrypt rate limits.

Keep the encryption key

Without the encryption key, the credentials in a restored database cannot be decrypted. Back up the whole n8n_data volume, not just exported workflows.

A simple backup of the n8n volume:

bash
cd /opt/n8n
docker compose stop n8n
docker run --rm -v n8n_n8n_data:/data -v /root:/backup alpine tar czf /backup/n8n-backup.tar.gz -C /data .
docker compose start n8n

Compose prefixes volume names with the folder name, so the volume is n8n_n8n_data. Check with docker volume ls.

Update n8n

The update procedure from the n8n documentation:

bash
cd /opt/n8n
docker compose pull
docker compose down
docker compose up -d

Make a backup before a major version change and read the release notes, because some updates change behaviour of nodes.

Basic security

  • Use a strong owner password and turn on two factor authentication in your n8n user settings.
  • Do not publish port 5678. Docker published ports bypass UFW, so the Compose file above leaves n8n without a ports: section on purpose.
  • Log in to SSH with a key and disable password login, as shown in how to connect via SSH.
  • Protect webhooks that trigger sensitive actions with header auth or basic auth in the Webhook node.
  • Send email through an HTTPS API. Outgoing mail ports on DataPasa are closed by default, so SMTP nodes will time out. Use a provider node such as Mailgun, SendGrid or Brevo, or read about outgoing mail ports.

Summary

You now have n8n on your own domain with automatic HTTPS, persistent data and a three command update routine. Build your first workflow, connect a webhook, and scale the VPS up when your automations grow. Plans for this setup are on the n8n hosting page.