Docker on Proxmox: LXC vs VM, Done Right

The right way to run Docker on Proxmox — why a dedicated VM beats a privileged LXC, how to set both up, and Portainer for a web UI. Avoid the docker-in-LXC pitfalls that cost real downtime.

Docker unlocks the enormous ecosystem of self-hosted apps — most projects ship a docker run command or a compose.yaml as their primary install method. But where you run Docker on Proxmox matters more than beginners expect. Get it wrong and a routine host kernel upgrade takes your services down.

Docker on Proxmox: LXC vs VM, Done Right — video walkthrough

This guide covers the real decision — LXC vs VM for Docker — the setup for both, and Portainer for a friendly web UI.


The decision: VM, almost always

Here’s the short version, then the reasoning:

Docker in a VM (recommended) Docker in an LXC
Kernel Its own — behaves as documented Shared with host
Upgrades Clean, isolated Can break on host kernel upgrade
Overhead ~500 MB–1 GB base RAM Very low
Isolation Strong Weak (esp. if privileged)
Best for Your real Docker host One throwaway lightweight app

Docker and LXC are both Linux container systems. Running Docker inside LXC nests two layers of namespaces and cgroups that were never meant to stack — it works with the right features enabled, but it’s fragile. A VM gives Docker its own kernel and behaves exactly as every tutorial online assumes. Unless you’re squeezing a single tiny app onto an already-busy node, use a VM.

The honest exception

For one lightweight, stateless app on a RAM-constrained node, a nesting-enabled unprivileged LXC running Docker is fine — as long as you’re happy to rebuild it if a Proxmox upgrade breaks it. For everything else, the VM is worth the extra half-gig of RAM.


1Create a Debian VM10 min

Create a VM following the first-VM walkthrough: Debian 12, 2 vCPU, 4 GB RAM, 32 GB disk, QEMU guest agent enabled. A cloud-init template makes this instant if you have one.

2Install Docker Engine3 min

Inside the VM, use Docker’s official convenience script, then verify:

Install Docker Engine on Debian

curl -fsSL https://get.docker.com | sh
docker run --rm hello-world

Add your user to the docker group so you don’t need sudo for every command:

Run docker without sudo

usermod -aG docker youradmin

Log out and back in for the group change to take effect.


Task 2: The LXC path (only if you must)

1Create a nesting-enabled unprivileged container3 min

If you’re deliberately going the LXC route, the container needs the nesting and keyctl features:

Create an LXC ready for Docker

pct create 120 local:vztmpl/debian-12-standard_12.7-1_amd64.tar.zst \
--hostname docker01 \
--cores 2 --memory 2048 --swap 512 \
--rootfs local-lvm:16 \
--unprivileged 1 --features nesting=1,keyctl=1 \
--net0 name=eth0,bridge=vmbr0,ip=dhcp \
--onboot 1 --password --start 1

Then install Docker inside it exactly as in Task 1. See the Proxmox LXC docs on the feature flags.

Expect maintenance

Docker-in-LXC can break after a Proxmox host kernel upgrade — storage driver mismatches are the usual culprit. Keep your compose files and volumes backed up so the container is disposable.


Task 3: Add Portainer

1Run Portainer as a container3 min

Portainer gives you a web UI over your Docker host. Deploy it with a persistent volume:

Deploy Portainer CE

docker volume create portainer_data
docker run -d \
--name portainer \
--restart=always \
-p 9443:9443 \
-v /var/run/docker.sock:/var/run/docker.sock \
-v portainer_data:/data \
portainer/portainer-ce:latest

Open https://<docker-host-ip>:9443, create the admin account within a few minutes of first launch (a security timeout), and you’re in. From here you can deploy stacks (compose files) straight from the UI.

Nicer URLs

Rather than :9443 everywhere, put Portainer and your apps behind a reverse proxy with names from Pi-hole local DNS — e.g. https://portainer.homelab.lan.


What’s next

You’ve got a stable Docker host and a UI to manage it. Now make your services reachable at clean HTTPS URLs with a reverse proxy, and don’t forget to back up the VM — your compose files and volumes live there.


Related posts: