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.
Install n8n on Proxmox VE Using Docker Inside an LXC Container
By the end of this walk‑through you will have a Proxmox VE host running a Debian‑based LXC container that contains Docker Engine and a docker‑compose stack for the official n8n image. An nginx reverse proxy on the host will expose n8n over HTTPS at a domain of your choice, complete with basic authentication. The entire process takes roughly 45 minutes to an hour, depending on your internet speed and how familiar you are with the Proxmox web interface.
More Tutorials & Self-Hosting guides on TechPulseMind →
Prerequisites
Before you begin, make sure you have the following items ready. If any item is missing, the steps that depend on it will fail.
| Item | Minimum Requirement | Notes / How to Verify |
|---|---|---|
| Proxmox VE host | Proxmox VE ≥ 7.0 (latest stable recommended) | Run pveversion in the host shell to see the version. |
| CPU / RAM / Disk | 2 vCPU, 2 GB RAM, 10 GB+ disk for the LXC (adjust per expected workload) | Check free resources in the Proxmox GUI → Datacenter → Summary. |
| Network | Static IP on the host, internet access for template and Docker pulls | Ping 8.8.8.8 and verify DNS resolution. |
| Root / sudo access | Ability to create LXC containers and run commands inside them | Test by running pct list or creating a dummy container. |
| Template repository | Proxmox template server enabled – a recent Debian or Ubuntu LXC template (e.g., Debian 11) | In GUI: local (proxmox) → CT Templates → Templates; ensure at least one template is present. |
| Domain name (optional but recommended for HTTPS) | A fully‑qualified domain name that points to the host’s public IP (or a port‑forwarded IP) | Verify with dig +short your‑domain.tld. |
| Port availability | Host ports 80 and 443 free for the reverse proxy | Check with ss -tlnp | grep ':80\|:443'. |
| Basic Linux CLI knowledge | Ability to edit files (nano/vim), run systemctl, docker, docker‑compose |
No specific version required; we will use the officially documented installation methods. |
If you are unsure about the exact name of the current LXC template, consult the Proxmox template repository in the GUI; the version may change over time.
Step‑by‑Step Procedure
-
Prepare the Proxmox Host
First we update the host operating system so that we have the latest security patches and package metadata. This step is safe; it only downloads and installs updates.
Log in to the Proxmox web GUI or via SSH as root or a user with sudo privileges. Then run the update and upgrade commands:
apt update && apt upgrade -yThe
apt updaterefreshes the package index, whileapt upgrade -yinstalls any available upgrades without prompting for confirmation.If a new kernel was installed, reboot the host to load it:
rebootVerify: After the host comes back online, run
pveversionto confirm you are running a supported version, and runapt list --upgradableto ensure no pending upgrades remain. -
Download and Deploy an LXC Template
We will create a Debian‑based LXC container that will host Docker. In the Proxmox GUI navigate to local (proxmox) → CT Templates → Templates. If the list is empty, click the Templates button and then Update to sync the template repository.
Select a recent Debian template (for example, Debian 11 Bullseye). Note the storage name where the template resides (e.g.,
local-lvm) and the exact filename of the template file (e.g.,debian-11-standard_11.0-1_amd64.tar.xz). You will need these values for the CLI command.Now create the container. Choose an unused container ID (CTID), for example
101. Run the following command, replacing the placeholders with the values you noted:pct create 101 local-lvm:debian-11-standard_11.0-1_amd64.tar.xz \ -hostname n8n-lxc \ -cores 2 \ -memory 2048 \ -swap 512 \ -rootfs local-lvm:8 \ -net0 name=eth0,bridge=vmbr0,ip=dhcp \ -features nesting=1Explanation of the flags:
-hostnamesets the container’s hostname.-coresand-memoryallocate CPU and RAM.-swapadds a small swap file.-rootfsdefines the size of the container’s root filesystem.-net0attaches the container to the host’s bridgevmbr0and requests an IP via DHCP.-features nesting=1enables nesting, which is required for Docker’s overlayfs storage driver to work inside the container.
Verify: Run
pct list. You should see the new container with statusstoppedand the CTID you chose. -
Start the Container and Access It
Start the container we just created:
pct start 101Then open a console. You can do this via the Proxmox GUI (select the container → Console) or via the command line:
pct enter 101You will be dropped into a root shell inside the container. By default there is no password for the root account; you can set one with
passwdif you wish.Verify: Your prompt should look something like
root@n8n-lxc:~#, indicating you are inside the container. -
Update the Container OS and Install Prerequisites
Now that we have a shell inside the LXC, we update its package list and install the tools needed to add Docker’s repository.
apt update && apt upgrade -yThis refreshes the container’s package index and applies any available upgrades.
Next install the prerequisite packages:
apt install -y curl gnupg2 lsb-release ca-certificatescurldownloads files,gnupg2handles GPG keys,lsb-releaseprovides distribution information, andca-certificatesensures SSL verification works.Verify: Run
curl --versionandgnupg --version; both should return version information without errors. -
Install Docker Engine (Official Method)
We will install Docker using the official Docker APT repository, which ensures we get a recent, supported version.
First add Docker’s GPG key:
curl -fsSL https://download.docker.com/linux/$(. /etc/os-release; echo "$ID")/gpg | \ sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpgThis command fetches the key from Docker’s site, de‑armors it, and stores it in a trusted keyring.
Next set up the stable repository:
echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] \ https://download.docker.com/linux/$(. /etc/os-release; echo "$ID") \ $(lsb_release -cs) stable" | \ sudo tee /etc/apt/sources.list.d/docker.list > /dev/nullThis creates a file
/etc/apt/sources.list.d/docker.listthat tells APT where to find Docker packages.Update the package index again and install Docker:
apt update apt install -y docker-ce docker-ce-cli containerd.io docker-compose-pluginThe packages installed are:
docker-ce– the Docker Engine.docker-ce-cli– the Docker command line client.containerd.io– the container runtime.docker-compose-plugin– enables thedocker composesubcommand.
Enable and start the Docker service so it runs on boot:
systemctl enable --now dockerIf you prefer not to type
sudofor every Docker command, add your user to thedockergroup. Inside the container the default user isroot, so this step is optional, but we include it for completeness:usermod -aG docker $USER newgrp docker # or log out and back inVerify: Check that Docker is installed and running:
docker versionYou should see both Client and Server sections with version numbers.
Run a quick test container:
docker run --rm hello-worldIf the installation succeeded, Docker will download the
hello-worldimage and print a message beginning with “Hello from Docker!”. -
Create a Directory for n8n Data and docker‑compose File
We will keep all n8n‑related files under
/opt/n8ninside the container. This makes backups straightforward.mkdir -p /opt/n8n cd /opt/n8nNow create a
docker-compose.ymlfile. We will use the official n8n image and enable basic authentication for simplicity. Replace the placeholder values with a username and password of your choice, and set the host variable to the domain or IP you plan to use for the reverse proxy.version: "3.8" services: n8n: image: n8nio/n8n:latest container_name: n8n restart: unless-stopped ports: - "5678:5678" environment: - N8N_BASIC_AUTH_ACTIVE=true - N8N_BASIC_AUTH_USER=your_username - N8N_BASIC_AUTH_PASSWORD=your_strong_password - N8N_HOST=your-domain.tld - N8N_PROTOCOL=https - NODE_ENV=production volumes: - ./data:/home/node/.n8nExplanation of key sections:
- The
portsline maps container port 5678 to the same port on the container’s localhost, which the host‑side nginx will proxy to. - Environment variables enable basic auth, set the hostname n8n will generate links with, and force HTTPS.
- The
volumesline mounts a host directory./datainto the container so that workflows, credentials, and the database persist across container restarts.
Verify: Confirm the file exists and is syntactically correct:
ls -l docker-compose.yml docker compose configThe second command should output the parsed configuration without error.
- The
-
Pull and Start n8n via Docker Compose
With the compose file in place, we can start the stack.
docker compose up -dThe
-dflag runs the containers in the background.Give the container a few seconds to initialize, then check its status.
Verify:
- List the services:
docker compose psYou should see the
n8nservice with stateUp. - View the logs to ensure the application started correctly:
docker compose logs -f n8nLook for a line similar to “n8n is ready on http://0.0.0.0:5678”.
- Test the health endpoint from inside the container (or from the host, since the port is bound locally):
curl -s http://localhost:5678/healthzA successful response will be a 200 OK or a JSON payload containing
{"status":"ok"}.
- List the services:
-
Install and Configure a Reverse Proxy (nginx) on the Proxmox Host
We will now install nginx on the Proxmox host itself (not inside the container) and configure it to forward traffic to the n8n service running on the container’s localhost port 5678.
Warning: The next command removes the default nginx site. If you are already using nginx for other purposes on this host, back up your existing configuration first.
apt install -y nginxThis installs the nginx web server.
Remove the default site to avoid conflicts:
rm /etc/nginx/sites-enabled/defaultCreate a new site configuration for n8n. Use your preferred editor (
nanoorvim) to create/etc/nginx/sites-available/n8n-proxywith the following content. Replaceyour-domain.tldwith the actual domain you intend to use (or the host’s public IP if you do not have a domain).server { listen 80; server_name your-domain.tld; location / { proxy_pass http://127.0.0.1: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; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 86400; } }Explanation of the proxy settings:
proxy_passforwards the request to the n8n service listening on localhost port 5678.- The various
proxy_set_headerlines preserve important information about the original request (host, client IP, protocol) so that n8n can generate correct URLs and handle WebSocket connections. proxy_http_version 1.1and theUpgrade/Connectionheaders are required for proper WebSocket support, which n8n uses for real‑time updates.
Enable the site by creating a symlink in the
sites-enableddirectory:ln -s /etc/nginx/sites-available/n8n-proxy /etc/nginx/sites-enabled/Test the nginx configuration for syntax errors:
nginx -tIf the test passes, reload nginx to apply the new configuration:
systemctl reload nginxVerify:
- Run
nginx -tagain; it should report “syntax is ok” and “test is successful”. - Check the service status:
systemctl status nginxIt should show
active (exited). - From a computer on the same network, open a web browser and navigate to
http://your-domain.tld. You should see a basic authentication dialog (because we enabledN8N_BASIC_AUTH_ACTIVE). Enter the username and password you set in the compose file. After authenticating, the n8n workflow editor should load.
-
(Optional) Secure the Proxy with TLS Using Let’s Encrypt
If you have a domain that points to the host’s public IP, you can obtain a free TLS certificate from Let’s Encrypt to serve n8n over HTTPS. This step is optional but strongly recommended for any production or externally accessible instance.
Install Certbot and the nginx plugin:
apt install -y certbot python3-certbot-nginxObtain and install the certificate. Replace
your-domain.tldwith your actual domain:certbot --nginx -d your-domain.tldFollow the prompts. Certbot will automatically modify the nginx site to listen on port 443 and add the necessary SSL directives. It will also ask whether you want to redirect HTTP traffic to HTTPS; choosing the redirect is advisable.
Certbot installs a systemd timer that will automatically renew the certificate before it expires. You can test the renewal process:
certbot renew --dry-runVerify: Open
https://your-domain.tldin a browser. You should see a padlock icon indicating a valid certificate, and the n8n login page should appear after you pass the basic‑auth prompt. -
Ensure the LXC Container Starts on Boot
Finally, configure the container to start automatically when the Proxmox host boots.
In the Proxmox GUI, select the container → Options → Start at boot → set to Yes. Alternatively, run the following command on the host, replacing
101with your container ID:pct set 101 -onboot 1Verify: Reboot the Proxmox host:
rebootAfter the host returns online, run
pct list. The container should appear with statusrunning. Then, inside the container (or viapct enter 101), rundocker compose psto confirm the n8n service isUp.
Verification Summary (Milestones)
| Milestone | How to Verify |
|---|---|
| Host updated and functional | pveversion shows a supported version; apt list --upgradable returns none. |
| LXC container created and running | pct list |
| Docker Engine installed inside container | docker version prints Client and Server sections; docker run --rm hello-world succeeds. |
| n8n stack deployed via docker‑compose | docker compose ps |
| Reverse proxy forwarding to n8n | Visiting http://your-domain.tld (or HTTPS if TLS enabled) shows the n8n login page after basic auth. |
| Container starts on host boot | After a host reboot, pct list |
Troubleshooting Common Failures
Below are the most frequent issues encountered when following this guide, along with steps to resolve them.
1. Container fails to start or shows errors during pct start
Check the container’s log for clues:
pct status 101 --verbose
Common causes:
- Insufficient memory or disk allocated – increase the
-memoryor-rootfsvalues and recreate the container. - Missing nesting feature – ensure
-features nesting=1was included when creating the container; if omitted, destroy and recreate with the flag.
2. Docker installation fails with GPG errors
This usually means the system time is wrong, preventing verification of the repository key. Synchronize the clock:
apt install -y ntpdate
ntpdate-debian
Then repeat the Docker repository steps.
3. n8n container exits immediately
Inspect the logs:
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.