
LXC Containers vs KVM VMs in Proxmox: When to Use Which
Proxmox VE gives you two ways to slice a server: full virtual machines via KVM, and LXC system containers that share the host's kernel. The right choice per workload is usually clear once you know the three questions that decide it — isolation, kernel, and migration. This guide explains how each actually works, compares them on the dimensions that matter operationally, settles the Docker question with Proxmox's own current guidance, and ends with a decision table you can apply per service.
10 July 2026
by Jesse Schokker
Proxmox
LXC
KVM
Virtualization
Loading...
Answer first: three questions decide it
For any given workload, ask:
- Does it need its own kernel? A different OS (Windows, BSD), a specific kernel version, kernel modules, or deep kernel tuning → VM. Containers share the host's kernel, full stop.
- How strong must the isolation be? Untrusted code, tenant separation, compliance boundaries → VM. The hardware-virtualisation boundary is categorically stronger than namespace isolation.
- Will you need to move it without stopping it? Live migration between cluster nodes is VM-only — containers move via a stop-and-restart.
If all three answers are "no" — a trusted, Linux-based, restartable service — an LXC container gives you the same workload in a fraction of the footprint, booting in about a second. That describes a lot of real infrastructure: reverse proxies, DNS, internal tools, per-app service instances. Which is why the practical Proxmox pattern is mixed: VMs for the crown jewels and anything foreign, containers for the fleet of small Linux services around them.
How each actually works
A KVM virtual machine is a complete computer in software: QEMU presents virtual hardware, KVM (the kernel's hypervisor module) executes guest code with hardware acceleration, and the guest runs its own kernel on that hardware from its own disk image. The host sees one process; the guest genuinely doesn't know it's virtualised (mostly — the paravirtualised VirtIO drivers exist precisely to let it cooperate for speed).
An LXC container is not a computer — it's a partitioned view of the host's kernel. Namespaces give it private process trees, network stacks, and filesystems; cgroups meter its CPU and memory. There is no second kernel, no virtual hardware, no boot process beyond starting init. That's why a container starts in a second and adds near-zero per-instance overhead — and why every container on the host lives or dies with the host's one kernel.
Proxmox treats both as first-class: same GUI, same storage backends, same vzdump/PBS backups, same firewall and snapshot workflow. The differences below are inherent to the technologies, not Proxmox limitations.
| Dimension | KVM VM | LXC container |
|---|---|---|
| Guest OS | Anything (Linux, Windows, BSD…) | Linux only, host's kernel |
| Isolation | Hardware-virtualisation boundary | Kernel namespaces (weaker) |
| Overhead per instance | Guest kernel + reserved RAM + virtual hw | Near zero |
| Boot time | OS boot (tens of seconds) | ~1 second |
| Live migration | Yes | No — restart migration only |
| Memory | Allocated to the guest (ballooning helps) | cgroup limit; unused RAM stays host-usable |
| Kernel control | Full (own kernel, modules) | None |
| PCIe/GPU passthrough | Yes (VFIO) | Device-level only, no VFIO |
| Snapshots, backups, HA | Yes | Yes (HA = restart on another node) |
Density and overhead: the honest version
Proxmox publishes no official "X containers per VM-equivalent" number, and you should distrust anyone who does — density depends entirely on workload. But the mechanism is uncontroversial and worth understanding:
- Every VM pays a fixed tax: its own kernel and system processes, plus its allocated memory, which is held whether the guest uses it or not (ballooning claws some back, imperfectly). Twenty small VMs means twenty kernels and twenty memory reservations.
- Twenty containers share one kernel and one page cache, and their cgroup memory limits are ceilings, not reservations — RAM a container isn't using is simply free host RAM.
For CPU-bound work, the throughput difference is small — KVM's hardware-assisted execution is efficient, and a busy VM is nearly as fast as a busy container. The gap shows up in memory economics and per-instance overhead: on a host running many small services, containerising them routinely multiplies how many fit, less because containers are "faster" than because VMs reserve what idle services never use. Size the host with our sizing guide's virtualisation rules either way — RAM is the binding constraint in both models.
Isolation: what "unprivileged" buys, and what it doesn't
Proxmox creates containers unprivileged by default, and you should keep it that way: the container's root maps to a harmless high-numbered UID on the host, so a full container-root compromise lands the attacker in an unprivileged host account. Combined with AppArmor, seccomp, and cgroups, an unprivileged LXC is a respectable boundary for trusted workloads.
It is still not a VM boundary. Every container syscall hits the host kernel directly — the attack surface between container and host is the entire kernel interface, versus a VM's much narrower hypervisor interface. The practical rules that fall out:
- Untrusted or internet-exposed-and-high-risk code, other tenants, compliance-separated workloads → VM. This is what the stronger boundary is for.
- Privileged containers (the non-default) weaken the story substantially — treat them as a legacy escape hatch, not an option. If a workload "needs" a privileged container, it usually actually wants a VM.
- Containers with
nestingenabled (for Docker and systemd conveniences) relax isolation further — fine for trusted internal services, another point against using it for anything sketchy.
The Docker question
The most-asked version of this comparison is really "where do my Docker containers go?" Proxmox's own current guidance, softened over the years but consistent in direction: for production — especially where isolation or live migration matter — run Docker inside a VM, not inside an LXC container. Docker-in-LXC (with nesting enabled) is popular in homelabs because it skips a VM's overhead, but it stacks two container runtimes on one kernel and has a history of breaking on host upgrades — the kind of fragility you accept in a lab and regret in production.
Worth knowing as it matures: since PVE 9.1, Proxmox can create containers directly from OCI images (the Docker image format) as a technology preview — pull an image and run it as a Proxmox-managed application container, no Docker daemon involved. It's genuinely promising as the eventual native answer, but "technology preview" means exactly that; the boring VM remains the production recommendation while this settles.
So: one "Docker host" VM (or a few, by trust domain), Docker inside it, and Proxmox manages the VM — you get VM-grade isolation, live migration for the whole Docker estate, and clean host upgrades.
What only VMs can do — and what LXC does best
Beyond the three deciding questions, the concrete VM-only list: Windows and other non-Linux guests, custom/newer kernels than the host's, kernel modules (WireGuard is in-kernel already, but e.g. specialised storage or research modules), PCIe passthrough via VFIO (GPUs for transcoding or AI, HBAs for a NAS guest), and — operationally the big one — live migration and hypervisor-independent portability (a VM disk image moves to any KVM host; a container config is more entangled with its host).
LXC's home turf, correspondingly: the many-small-services pattern. A container per service — DNS here, reverse proxy there, a Postgres for this app, a monitoring stack — each independently snapshottable, backed up, resource-limited, and restartable, at a per-instance cost low enough that "one service, one container" is affordable as a policy. Bind mounts add a quiet superpower: mounting host directories directly into containers, no network filesystem required — natural for a container that processes data living on the host's big ZFS pool.
One cluster caveat to plan around: container "migration" between nodes is restart migration — stop, move, start (seconds of downtime for a light container, but downtime). HA works the same way: a failed node's containers restart elsewhere. If a service can't tolerate that, it belongs in a VM — that's question 3 doing its job.
The decision table
| Workload | Verdict | Why |
|---|---|---|
| Windows anything | VM | Foreign kernel — no other option |
| Production database | VM (usually) | Isolation, live migration for maintenance, memory control |
| Docker/Kubernetes host | VM | Proxmox's own recommendation; clean upgrades |
| Reverse proxy, DNS, internal tools | LXC | Small, trusted, restartable — the sweet spot |
| Per-app services (game servers, bots, runners) | LXC | Density; one-service-one-container policy |
| Untrusted / tenant workloads | VM | The boundary is the product |
| GPU transcoding (Jellyfin etc.) | VM + passthrough | VFIO is VM-only |
| NAS/storage appliance | VM (HBA passthrough) or LXC + bind mounts | Depends whether it owns disks or borrows paths |
| Firewall/router (OPNsense) | VM | It's BSD — and you want it isolated anyway |
Frequently asked questions
Can I convert a container to a VM later (or vice versa)?
There's no one-click conversion — the disk contents are compatible (it's all Linux filesystems) but the packaging differs: a VM needs a kernel, bootloader, and init that a container image doesn't carry. The practical route is redeploy-and-migrate-data, which is rarely painful for the small services containers host. The asymmetry is worth noting at deployment time: "start as a VM, containerise later" wastes only resources, while "start as LXC, VM-ise later" costs a migration — when genuinely unsure, the VM is the reversible-ish choice.
How much faster is LXC really?
For raw compute, barely — KVM executes guest CPU instructions with hardware assistance, so a number-crunching VM is within a few percent of native. The honest differences: boot time (a second versus an OS boot), memory economics (ceilings versus reservations — this is where density comes from), and I/O path length (container I/O is host I/O; VM I/O crosses VirtIO, which is fast but not free). If your motivation is "performance", measure first; if it's "fitting 30 small services on one box", LXC's case makes itself.
Do containers work with Proxmox HA and clustering?
Yes, with one behavioural difference: no live migration. Moving a container between nodes — for maintenance or by HA after a node failure — is stop-transfer-start, so plan for seconds-to-a-minute of downtime per move rather than the imperceptible cutover VMs get. For most container-class services that's fine (and HA restarting your DNS container on a surviving node beats it staying down); for anything where it isn't, see question 3 and use a VM. Cluster mechanics are covered in our HA guide.
Should my whole setup just be VMs for simplicity?
It's a defensible simplification — one model, strongest isolation everywhere, live migration for everything — and if your services are few and RAM is plentiful, take it. The cost is density: idle VMs reserve memory that idle containers wouldn't, so the all-VM fleet needs a bigger host for the same workload. Most operators converge on the mix this article describes once the service count grows; there's no prize for purity in either direction.
Deploying on Serverside
Both models want the same substrate: cores, RAM, and fast NVMe. Our Proxmox dedicated servers come pre-installed and provisioned in under a minute on ASN 55285 — with enough RAM options to run the all-VM fleet if that's your style, private networking for multi-node setups, and KVM-over-IP for the host itself. Size the box with the server sizing guide (sum your guests, RAM is the constraint), then build out with the rest of the series: initial setup, networking, and backups.

About the author
Jesse SchokkerCo-founder & CTO, Serverside.com
Jesse is the co-founder and CTO of Serverside.com, where he leads the engineering behind the company's bare-metal cloud — from the ASN 55285 backbone to sub-minute server provisioning. He writes about dedicated servers, operating systems, and running production workloads on bare metal.


