Independent tech intelligence, checked against primary sources.

TechPulseMind Useful technology.
No manufactured hype.

How to Install n8n on Proxmox VE Using Docker Inside an LXC Container

Step‑by‑step guide to install n8n on Proxmox VE using Docker inside an LXC container, with nginx reverse proxy and optional Let’s Encrypt TLS.

How to Install n8n on Proxmox VE Using Docker Inside an LXC Container

Before you start: versions, package names and storage identifiers change over time. Check the commands against the official documentation for your setup before running them, especially anything that creates, deletes or overwrites data.

This guide deploys n8n in a Docker container inside an LXC on Proxmox VE: create the container, install Docker, run n8n with Compose, and put it behind a reverse proxy correctly.

If you are following an older version of this guide or a similar one elsewhere, three things in it are now wrong, and each will stop you cold. They are corrected in place below.

Prerequisites

  • A working Proxmox VE host with root SSH or console access
  • A free VMID and an IP for the container
  • Roughly 2 GB RAM and 8 GB disk for the container

Step 1: Download a container template

Templates are not on local-lvm. They live on a storage that accepts the vztmpl content type — normally local — and are referenced as local:vztmpl/<file>. Referencing a template on local-lvm is the first thing that will fail.

pveam update
pveam available --section system | grep debian
pveam download local debian-12-standard_12.7-1_amd64.tar.zst
pveam list local

Use the exact filename pveam available prints; the version suffix changes over time.

Step 2: Create the container

pct create 210 local:vztmpl/debian-12-standard_12.7-1_amd64.tar.zst \
  --hostname n8n \
  --cores 2 \
  --memory 2048 \
  --swap 512 \
  --rootfs local-lvm:8 \
  --net0 name=eth0,bridge=vmbr0,ip=192.168.10.50/24,gw=192.168.10.1 \
  --unprivileged 1 \
  --features nesting=1 \
  --onboot 1

Two of those flags carry weight:

  • --features nesting=1 is what allows Docker to run inside the container. Without it you get Cannot connect to the Docker daemon later.
  • --unprivileged 1 keeps root inside the container mapped to an unprivileged user outside. You do not need a privileged container for Docker — that is covered in detail, with the correct pct syntax, in running Docker inside an LXC without going privileged.

A static IP is worth setting here rather than DHCP, because the reverse proxy step depends on the address not moving.

pct start 210
pct exec 210 -- bash

Step 3: Install Docker

apt update && apt upgrade -y
curl -fsSL https://get.docker.com | sh
systemctl enable --now docker
docker info

Use the official script rather than apt install docker.io, which installs whatever version the distribution froze at. If docker info returns the socket error instead of system information, nesting is not enabled — go back to step 2.

Step 4: The Compose file

Create /opt/n8n/compose.yaml:

services:
  n8n:
    image: docker.n8n.io/n8nio/n8n:latest
    container_name: n8n
    restart: unless-stopped
    ports:
      - "5678:5678"
    environment:
      - GENERIC_TIMEZONE=Europe/Rome
      - TZ=Europe/Rome
      - N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true
      - N8N_RUNNERS_ENABLED=true
    volumes:
      - n8n_data:/home/node/.n8n

volumes:
  n8n_data:

Three corrections are baked into that file:

No version: key. The top-level version property is obsolete. Docker’s documentation states it “is only informative and you’ll receive a warning message that it is obsolete if used”, and that Compose “always uses the most recent schema to validate the Compose file, regardless of the version field”. If your file starts with version: "3.8", delete that line.

No N8N_BASIC_AUTH_* variables. This is the big one. Support for basic auth was removed in n8n 1.0, along with N8N_USER_MANAGEMENT_DISABLED. User management is mandatory now. Setting N8N_BASIC_AUTH_ACTIVE=true does nothing, and if you are relying on it for protection you have an unprotected instance. You create the owner account in the browser on first visit instead.

A named volume, not a bind mount to ~/.n8n. The n8n container runs as the node user, and bind-mounting a host directory owned by root produces a permission error on startup — the subject of the EACCES /home/node/.n8n fix. A named volume avoids the ownership mismatch entirely.

That volume matters more than it looks: /home/node/.n8n holds the encryption key for your stored credentials. Lose it and every credential in your workflows becomes unreadable, even with a database backup.

Step 5: Start it

cd /opt/n8n
docker compose config
docker compose up -d
docker compose ps
docker compose logs -f n8n

docker compose config renders the file with substitutions applied and fails loudly on a syntax error — cheaper than debugging a container that will not start.

Then open http://<container-ip>:5678 and create the owner account. If the port does not answer, see fixing “address already in use” on port 5678.

Step 6: Reverse proxy — and the mistake to avoid

Older versions of this guide told you to install nginx on the Proxmox host and proxy to 127.0.0.1:5678. That cannot work. n8n is listening inside the LXC, not on the host’s loopback interface, so the host proxies to a port nothing is bound to and you get a 502.

If you put nginx on the host, it must target the container’s address:

location / {
    proxy_pass http://192.168.10.50:5678;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;

    # n8n's editor uses websockets; without these the UI silently fails to update
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

Better still, do not put nginx on the Proxmox host at all. The host runs your hypervisor; adding a public-facing web server to it widens the blast radius of the one machine you cannot afford to lose. Run the proxy in its own container, or skip inbound ports entirely with a Cloudflare Tunnel.

Whichever you choose, tell n8n its public address, or generated webhook URLs will point at the internal IP:

      - N8N_HOST=n8n.example.com
      - N8N_PROTOCOL=https
      - WEBHOOK_URL=https://n8n.example.com/

Troubleshooting

Symptom Cause
Cannot connect to the Docker daemon nesting=1 missing on the container
pct create cannot find the template Template referenced on local-lvm instead of local:vztmpl/
EACCES: permission denied, mkdir '/home/node/.n8n' Bind mount owned by root — use a named volume
address already in use on 5678 A previous container still holds the port
Login screen cannot be disabled Expected — user management is mandatory since 1.0
Editor UI loads but never updates Missing websocket headers on the proxy

Backups

Two independent things need backing up: the Proxmox container itself (vzdump), and the Docker volume holding n8n’s data and encryption key. The container backup does not capture volume contents in a form you can restore selectively — see backing up a Docker homelab.

Sources

Related reading

Some links on this page may be affiliate links. If you buy through them we may earn a commission at no extra cost to you. See our affiliate disclosure.