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.
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=1is what allows Docker to run inside the container. Without it you getCannot connect to the Docker daemonlater.--unprivileged 1keeps 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 correctpctsyntax, 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
- n8n docs — Install with Docker (image, port, volume, timezone and permissions variables)
- n8n docs — User management (basic auth removed in 1.0)
- Docker docs — Compose file version and name (the
versionkey is obsolete) - Proxmox VE docs — Linux Container (
pveam, templates,pct create)
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.