Proxmox LXC vs VM vs Docker: Which Should You Use?

Short answer: On Proxmox, use an LXC container for lightweight Linux services (DNS, reverse proxies, databases) because it shares the host kernel and barely touches your RAM. Use a VM when you need Windows, a different kernel, hard isolation, or PCIe passthrough. Run Docker inside a VM for app stacks — that's the officially recommended path.

Every time you click "Create" in Proxmox you pick one of two guest types: a VM or an LXC container. Docker is the third option people argue about, even though it isn't a Proxmox guest type at all. The Proxmox LXC vs VM decision comes down to one thing — whether the guest borrows the host's kernel or boots its own — and once that clicks, the rest of the choices fall into place. Here's how I decide, with the commands and the failure modes I've actually hit.

Proxmox LXC vs VM vs Docker at a glance

  LXC container KVM virtual machine Docker (inside a VM)
KernelShares the host kernelBoots its own kernelShares the VM's kernel
Boot timeSecondsTens of secondsSub-second per container
Idle RAM costOnly what the service usesExtra ~256–512 MB for the guest OSOnly what the app uses
IsolationNamespaces + cgroups (weaker)Hardware-level (strong)App-level, inside the VM
Guest OSLinux onlyAnything: Windows, BSD, LinuxLinux app image
Live migrationNo (restart migration)YesMigrates with its VM
GPUDevice passthrough, shareableFull PCIe passthrough, dedicatedVia its VM
BackupsNative (vzdump / PBS)Native (vzdump / PBS)Back up the VM + volumes
Best forLightweight Linux servicesWindows, isolation, kernel controlApp packaging, Compose stacks

What's actually different? The kernel is the whole story

A VM and a container solve the same problem in opposite ways, and the split is the kernel.

LXC containers (system containers)

Proxmox uses LXC through its own toolkit, pct (Proxmox Container Toolkit). An LXC container is an isolated group of processes with its own filesystem, network stack, and process tree — but it runs directly on the host's kernel. There's no emulated hardware and no second kernel to boot. That's why a container starts in a second or two and only uses the RAM its processes need. You SSH in, run apt, start nginx, and it behaves like a tiny Linux box.

The catch: because it shares the host kernel, an LXC container can't run Windows, can't load a kernel module the host doesn't have, and can't run a different kernel version than your Proxmox node. Isolation is done with kernel namespaces, cgroups, AppArmor, and seccomp — good, but not a hardware wall.

By default Proxmox creates unprivileged containers, where root (UID 0) inside the container maps to an unprivileged user on the host. That's the safe default and you should keep it unless something forces your hand. Privileged containers drop that mapping and should stay in trusted environments only — the LXC team won't even issue CVEs for escapes from privileged containers.

Virtual machines (KVM/QEMU)

A VM under Proxmox is QEMU plus the Linux KVM module. It emulates a full machine and boots its own kernel and OS, running guest code close to native speed on the host CPU. The cost is a guest operating system you have to feed — each VM carries its own kernel and userland, which is where that extra couple hundred megs of RAM per VM goes.

What you get for it: real isolation, any operating system you like (Windows, BSD, a different Linux kernel), live migration between nodes with no downtime, and clean PCIe passthrough for a GPU or HBA. If a workload has to be walled off from everything else, or it isn't Linux, it's a VM. Full stop.

Docker (application containers)

Docker isn't a Proxmox guest type. Docker packages a single application and its dependencies into an OCI image and runs it on some Linux kernel — it needs a host to sit on. On Proxmox that host is either a VM or an LXC container. So "Proxmox vs Docker" is a category error: Proxmox is the infrastructure layer, Docker is the app-packaging layer, and most real setups run both.

One nuance worth knowing: Proxmox VE 9.1 added support for pulling OCI (Docker-format) images and running them as LXC application containers directly. It's a technology preview right now — useful to watch, but not the thing to build production on yet.

When should you use an LXC container?

Reach for LXC first for anything Linux where density and speed matter more than a hard isolation boundary:

  • DNS and ad-blocking (Pi-hole, AdGuard Home, Unbound)
  • Reverse proxies (Caddy, nginx, Traefik)
  • Databases (PostgreSQL, MariaDB, Redis)
  • Web apps and dev environments
  • Monitoring agents, small tools, and glue services

A Pi-hole in an LXC idles at well under 100 MB of RAM. Try that with a VM and you've paid for a whole guest OS to run one small service. On a modest homelab node you can run a dozen LXC services in the RAM one or two VMs would eat.

LXC is also, contrary to a common myth, good at GPU transcoding. Because it's device passthrough rather than PCIe passthrough, several containers can share one GPU by bind-mounting /dev/dri. A VM's PCIe passthrough dedicates the whole card to a single guest. If you want Jellyfin and Plex to share one iGPU, LXC is the easier road.

When do you actually need a full VM?

Use a VM when a container physically can't do the job, or when isolation is the point:

  • Windows or any non-Linux OS. No container will run these.
  • A different or custom kernel, or a workload that loads kernel modules.
  • Hard isolation — multi-tenant setups, untrusted code, or anything where a shared kernel is a compliance problem. Regulated data (HIPAA, PCI-DSS, CMMC) usually wants kernel-level separation, and containers sharing a host kernel don't clear that bar. VMs do.
  • Live migration with zero downtime. Proxmox live-migrates VMs; LXC containers get a restart migration — they briefly go down. If a service can't blink, it's a VM.
  • Dedicated PCIe passthrough — a GPU handed entirely to one guest, an HBA passed to a NAS VM, etc.
  • Appliances that expect to own the box: pfSense/OPNsense, TrueNAS, Home Assistant OS, Kubernetes nodes.

Where does Docker fit — and should you run it in an LXC?

Here's the opinionated part. You can run Docker inside an LXC container. Plenty of people do. But the Proxmox team's own recommendation is to install Docker inside a VM, and I agree with them for anything you care about.

Docker-in-LXC means two container layers sharing one kernel. To make it work you enable nesting (and often more) on the container:

# /etc/pve/lxc/<CTID>.conf
features: nesting=1,keyctl=1

Some Docker features need extra flags like fuse=1 or mknod=1, and stubborn cases push people toward a privileged container or a relaxed AppArmor profile — which is exactly the security boundary you don't want to sand down.

The real problem is maintainability. I've had a Docker-in-LXC stack come back from a host kernel update with the Docker daemon simply refusing to start — docker ps returns nothing, and restoring yesterday's backup doesn't fix it because the breakage is at the host/kernel seam, not in the container. This shows up on the Proxmox forums after nearly every major update. When two container runtimes fight over the same kernel and cgroups, the update math eventually goes against you.

So my default: one Debian VM, Docker inside it, everything in a single docker-compose.yml. Add Portainer if you like a GUI. That VM has its own kernel, so overlay2, cgroups v2, and namespaces all work with zero special flags, and a Proxmox update can't reach in and break your Docker daemon. The cost is a few hundred MB of RAM for the guest OS. On any modern host, that's noise.

How do I choose? A quick decision path

  1. Is it Windows, or does it need its own kernel / hardware passthrough? → VM.
  2. Is it a Docker/Compose app stack? → VM running Docker.
  3. Does it need hard isolation or live migration? → VM.
  4. Is it a plain Linux service where you want low overhead? → LXC container.
  5. Everything else → start with an LXC; promote to a VM only if it fights you.

Real commands

Grab a template first, then create the container. Check what's current with pveam available — version strings change.

# List and download a container template
pveam available --section system
pveam download local debian-12-standard_12.7-1_amd64.tar.zst

# Create an unprivileged Pi-hole container
pct create 101 local:vztmpl/debian-12-standard_12.7-1_amd64.tar.zst \
  --hostname pihole \
  --memory 256 \
  --cores 1 \
  --rootfs local-lvm:4 \
  --net0 name=eth0,bridge=vmbr0,ip=192.168.1.53/24,gw=192.168.1.1 \
  --unprivileged 1 \
  --start 1

Resize a running container on the fly (memory and cores apply after a restart; cpulimit is live):

pct set 101 --memory 1024
pct set 101 --cores 2
pct set 101 --cpulimit 0.5

Spin up a VM to host Docker:

qm create 300 --name docker-vm --memory 4096 --cores 4 \
  --net0 virtio,bridge=vmbr0 \
  --scsihw virtio-scsi-single \
  --scsi0 local-lvm:32 \
  --cdrom local:iso/debian-12.7.0-amd64-netinst.iso \
  --boot order=scsi0

After the OS install, install Docker the normal way and add the guest agent so Proxmox can do clean shutdowns and snapshots:

apt update && apt install -y qemu-guest-agent
curl -fsSL https://get.docker.com | sh
apt install -y docker-compose-plugin
docker compose version

Back up any guest — VM or container — with vzdump (or schedule it through Proxmox Backup Server):

vzdump 101 --storage local --mode snapshot --compress zstd

Gotchas I've hit

  • Bind mounts kill snapshots. Add a host bind mount to a container and Proxmox refuses to snapshot it — you'll see snapshot feature is not available. The bind-mounted data lives outside the container's storage, so there's nothing consistent to freeze. Keep snapshot-worthy state on the container's own rootfs or a managed volume.
  • Unprivileged UID mapping bites Docker volumes. Root inside an unprivileged container is a high-numbered UID on the host (e.g. 100000). Docker's own UID handling can collide with that and throw permission-denied on volumes. One more reason Docker prefers a VM.
  • LXC migration is a restart, not a live move. Don't plan a zero-downtime cluster failover around containers.
  • Backups aren't snapshots. A snapshot is a rollback point on the same node; it's not a copy you can restore elsewhere. Use vzdump / PBS for actual backups.

FAQ

Is LXC faster than a VM on Proxmox?

For startup and RAM, yes — an LXC container boots in seconds and skips the guest-OS overhead a VM pays for its own kernel. For raw CPU, KVM runs close to native, so the gap there is small. The practical win for LXC is density: more services per gigabyte of RAM.

Can I run Docker directly on the Proxmox host?

You can, but don't. Installing Docker on the hypervisor itself mixes your app runtime into the node that manages everything, and it isn't a supported pattern. Put Docker in a VM (or, if you must, an LXC), never on the host.

Should I use a privileged or unprivileged LXC container?

Unprivileged, which is the Proxmox default. Root inside maps to an unprivileged host user, so a container escape lands on a nobody account instead of host root. Only go privileged for a specific, trusted workload that genuinely needs it.

What's the difference between LXC and Docker?

LXC gives you a system container — a whole lightweight Linux userland with its own init, that you manage like a small server. Docker gives you an application container — one packaged app and its dependencies, portable across hosts. On Proxmox, LXC is a native guest type; Docker needs a Linux host (a VM or LXC) to run on.

Does Proxmox support Docker natively now?

Not as a first-class guest type. Proxmox VE 9.1 can pull OCI (Docker-format) images and run them as LXC application containers, but that's a technology preview. For anything real, run Docker inside a VM.

What's the best homelab setup?

The common one: LXC containers for lightweight infrastructure (DNS, reverse proxy, databases), one Debian VM running your Docker Compose stack for apps (media, dashboards, monitoring), and dedicated VMs for appliances like a firewall or NAS that want the whole box.

Pick by the kernel question and you'll rarely pick wrong: borrow the host kernel with LXC when the workload is trusted Linux, boot a separate one with a VM when it isn't. Docker rides along inside a VM. Start containers cheap, and only spend a VM when the job asks for it.

Official references worth bookmarking: the Proxmox Linux Container (LXC) wiki and the Proxmox VE FAQ.