Install n8n on Ubuntu 24.04 with Docker and Caddy

Step-by-step guide to install n8n on Ubuntu 24.04 with Docker and Caddy. SSL, reverse proxy, and production settings included.
An abstract background with undulating lines, presenting a harmonious interplay of shapes and colors.

Ubuntu 24.04 is now the go-to base for many VPS deployments. It’s stable, supported for years, and plays well with container workloads. If you want to run n8n in production, Docker and Caddy are a clean way to do it. Docker handles the app and dependencies, while Caddy gives you HTTPS and a reverse proxy without hours of manual config.

I’ll walk through a full installation, from a bare VPS to a working, SSL-enabled n8n instance. Along the way I’ll point out common pitfalls and some production tips.

Prerequisites

  • A fresh Ubuntu 24.04 VPS (1 vCPU / 2GB RAM minimum; 2 vCPU / 4GB recommended for production).
  • Root or sudo access via SSH.
  • A domain name (optional but recommended) pointing to your VPS IP.
  • Basic knowledge of Linux command line.

If you’d rather skip manual setup, you can always start from a ready-to-deploy n8n VPS with Docker and Caddy already preconfigured.

Buuuut…. let’s assume you’re doing this yourself 🙂

Step 1: Update and install dependencies

Always update first:

sudo apt update && sudo apt upgrade -y

Install the required packages:

sudo apt install -y curl git ufw

We’ll use UFW later to secure the firewall.

Step 2: Install Docker and Docker Compose

On Ubuntu 24.04, the Docker packages from the official repository are the best choice.

curl -fsSL https://get.docker.com | sudo sh

Add your user to the docker group (replace ubuntu with your username):

sudo usermod -aG docker ubuntu
newgrp docker

Check versions:

docker --version
docker compose version

Docker Compose is now built into the Docker CLI, so you can use docker compose directly.

Step 3: Set up project directory

Create a working directory for n8n:

mkdir ~/n8n && cd ~/n8n

Inside, create folders for data:

mkdir n8n_data db_data

Step 4: Configure Docker Compose

Here’s a production-ready Compose file using Postgres and Caddy:

services:
  n8n:
    image: n8nio/n8n
    restart: unless-stopped
    ports:
      - "5678:5678"
    environment:
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_HOST=postgres
      - DB_POSTGRESDB_PORT=5432
      - DB_POSTGRESDB_DATABASE=n8n
      - DB_POSTGRESDB_USER=n8n
      - DB_POSTGRESDB_PASSWORD=changeme
      - N8N_BASIC_AUTH_ACTIVE=true
      - N8N_BASIC_AUTH_USER=admin
      - N8N_BASIC_AUTH_PASSWORD=strongpassword
      - N8N_HOST=automation.example.com
      - N8N_PROTOCOL=https
      - WEBHOOK_URL=https://automation.example.com/
      - N8N_PORT=5678
    volumes:
      - ./n8n_data:/home/node/.n8n
    depends_on:
      - postgres

  postgres:
    image: postgres:15
    restart: unless-stopped
    environment:
      - POSTGRES_USER=n8n
      - POSTGRES_PASSWORD=changeme
      - POSTGRES_DB=n8n
    volumes:
      - ./db_data:/var/lib/postgresql/data

  caddy:
    image: caddy:2
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - ./caddy_data:/data
      - ./caddy_config:/config
    depends_on:
      - n8n

Notes

  • Replace automation.example.com with your domain.
  • Caddy will handle HTTPS automatically.
  • For security, change the Postgres and n8n credentials before launch.

Step 5: Write the Caddyfile

Create Caddyfile in the same directory:

automation.example.com {
  reverse_proxy n8n:5678
}

If you don’t have a domain, you can skip Caddy and access n8n at http://your-vps-ip:5678, but you won’t get SSL.

Step 6: Start the stack

Bring everything up:

docker compose up -d

Check logs:

docker compose logs -f n8n

After a few seconds, open your browser at https://automation.example.com and you should see the n8n login page.

Step 7: Firewall setup

Block everything except SSH, HTTP, and HTTPS:

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 80
sudo ufw allow 443
sudo ufw enable

Check with:

sudo ufw status verbose

Step 8: Backups and monitoring

This is the part most people forget. Postgres holds all workflows and execution history — if you lose it, you start from zero. At minimum:

  • Use pg_dump to back up the database daily.
  • Snapshot your VPS or use a backup service.
  • Enable incremental backups if your provider supports them.

For monitoring, I like Uptime Kuma for simple webhook checks and Grafana with Prometheus for deeper insights. See the Prometheus and Grafana monitoring guide for details.

Step 9: Going further

FAQ

Can I run this without Docker?

Yes, but it’s painful. Docker keeps everything isolated and reproducible.

Do I need a domain name?

Not strictly. You can run on IP only, but services like Stripe or GitHub require HTTPS callbacks. Domains plus Caddy solve this.

How do I upgrade later?

Pull the new image and restart:

docker compose pull n8n
docker compose up -d

Keep backups before upgrading.

Is 2GB RAM enough?

Yes, for light workloads. For anything beyond a few integrations, go 4GB+.

What if I don’t want to manage any of this?

That’s when a managed n8n VPS is worth it. It ships with Docker, Caddy, SSL, backups, and monitoring preconfigured so you can focus on workflows instead of infrastructure.