Proxmox VE can run two kinds of guest: a full virtual machine (KVM) or a Linux container (LXC). Both show up in the same web interface, both get a number and a name, and both can be backed up and migrated. That similarity hides a real architectural difference, and picking the wrong one means either wasted resources or a workload that won’t run at all.
The short version: a VM emulates a whole computer and boots its own operating system, while a container shares the host’s kernel and just isolates a set of processes. A VM can run Windows; a container can’t. A container starts in a second and sips RAM; a VM gives you stronger isolation and runs anything.
This guide explains what’s actually different under the hood, compares them on isolation, performance, and overhead, and gives clear rules for which to reach for. It targets Proxmox VE 8.x, where both are first-class and live side by side on the same host.
The core difference: shared kernel vs full machine
Everything else follows from one fact, so it’s worth getting straight first.
A KVM virtual machine is full hardware virtualization. Proxmox, using KVM and QEMU, presents the guest with virtual CPUs, virtual disks, a virtual network card, and virtual firmware. The guest boots its own operating system and its own kernel on top of that virtual hardware, with no idea it isn’t running on a physical machine. Because it brings its own kernel, it can be Windows, a BSD, a different Linux distribution, or anything else.
An LXC container is operating-system-level virtualization. There’s no virtual hardware and no second kernel. The container is a set of processes running directly on the host’s Linux kernel, walled off using kernel features — namespaces for isolation and cgroups for resource limits. It feels like a small independent Linux server, but it’s borrowing the host’s kernel to do everything.
VM vs container at a glance
| Kernel | VM runs its own kernel. Container shares the host kernel. |
|---|---|
| Guest OS | VM: almost anything (Windows, Linux, BSD). Container: Linux only. |
| Boot time | VM: seconds to a minute, like a real machine. Container: typically a second or two. |
| Memory overhead | VM: a fixed baseline per guest for its kernel and services. Container: minimal — only what the processes use. |
| Isolation | VM: strong, hardware-enforced. Container: process-level, weaker boundary to the host. |
| Density | VM: tens per host. Container: often hundreds of small ones. |
That kernel line is the one that decides most arguments. Share the host kernel and you get speed and density but you’re stuck with Linux and a thinner security wall. Bring your own kernel and you get freedom and isolation but you pay for it in resources.
Isolation: how strong is the wall?
Isolation is about what a compromised or misbehaving guest can reach.
A VM’s boundary is enforced by the CPU’s virtualization extensions. The guest kernel genuinely believes it owns the hardware, and breaking out of a VM to the host is hard — it takes a hypervisor-level exploit, which is rare and valuable. That makes VMs the right home for anything untrusted, anything internet-facing you don’t fully control, or any workload where a breach must not reach the host or its neighbors.
A container’s boundary is software inside the shared kernel. Namespaces hide other processes and cgroups cap resources, but every container is still talking to the same kernel. A kernel vulnerability is a shared risk, and the isolation, while good, is not the hard wall a VM gives you.
Performance and overhead
This is where containers shine, and it’s the usual reason people reach for them.
Because a container has no virtual hardware and no second kernel to boot, it starts almost instantly and carries almost no baseline cost. The memory it uses is essentially the memory its processes use. Disk and network I/O go more or less straight to the host. CPU work runs natively. For a fleet of small services — a DNS resolver, a reverse proxy, a handful of web apps — you can pack many containers onto a host that would groan under the same number of VMs.
A VM carries a fixed tax. Every VM boots a full OS, so each one spends some RAM and CPU just being a running computer before it does any useful work. Ten idle VMs each holding a baseline add up; ten idle containers barely register. KVM is hardware-accelerated and genuinely efficient, so for a single CPU-bound workload the difference is modest — but multiply by guest count and the container’s lighter footprint wins on density.
Storage interacts with both. Containers and VMs draw from the same Proxmox storage pools, and how you’ve laid that out affects performance either way — the LVM vs LVM-Thin vs ZFS comparison covers the trade-offs there. Containers tend to use a filesystem subvolume while VMs use a block device or qcow2 image, but both ride on the storage you configured for the host.
Windows needs a VM. Full stop.
This one comes up constantly, so it’s worth its own section. You cannot run Windows in an LXC container. Containers share the host’s Linux kernel, and Windows requires the Windows kernel. There’s no namespace trick that bridges that — it’s a fundamental limit, not a missing feature.
So anything Windows — a Windows Server domain controller, a Windows 11 desktop, a legacy Windows app — runs as a KVM virtual machine in Proxmox. The same goes for any OS that isn’t Linux: FreeBSD, OPNsense, a Windows-only appliance, all VMs.
The flip side: most Linux server software runs beautifully in a container, and a lot of it runs better there because of the lower overhead. The OS requirement is often the first and clearest signal of which guest type you need.
Privileged vs unprivileged containers
If you’ve settled on a container, there’s a second choice that matters for security: privileged or unprivileged. Proxmox defaults to unprivileged, and you should usually leave it there.
An unprivileged container uses a user-namespace mapping (idmap): the container’s root (UID 0) maps to a high, unprivileged UID on the host. So even if something gains root inside the container and escapes, on the host it’s a nobody with no real power. This is the safe default and the right choice for almost everything.
A privileged container maps the container’s root straight to host root. That makes certain things easier — bind-mounting host directories, passing through some devices, running software that’s fussy about UIDs — but it means a container breakout is a host root breakout. The convenience is real; so is the risk.
Unprivileged vs privileged LXC
| Root mapping | Unprivileged: container root maps to a non-root host UID. Privileged: container root = host root. |
|---|---|
| Security | Unprivileged: strong, the default. Privileged: a breakout means host root. |
| Use when | Unprivileged: nearly always. Privileged: only when a specific mount, device, or app needs it. |
| Set at | Creation time — there's no clean toggle afterward, so choose deliberately. |
A note on Docker inside Proxmox
People often want to run Docker containers, and they ask whether to run Docker inside an LXC container or inside a VM. The cleaner, better-supported answer is a VM: create a small Linux VM, install Docker in it, and run your containers there. You get proper isolation and you’re on the path the Docker tooling expects.
Running Docker inside an LXC container is possible but fiddly — it needs nesting enabled and sometimes a privileged container, which reintroduces the security concerns above. If you’re building anything serious with containers-on-containers, the VM route avoids a category of strange kernel and permission problems. For the Docker side of that setup, the Docker Compose beginner guide is a good starting point once the VM is up.
Migration and other practical differences
A few operational points decide real deployments beyond raw performance.
Live migration. KVM VMs can live-migrate between nodes in a cluster with no downtime, moving a running machine across hosts. LXC containers migrate too, but the move involves a brief restart rather than a seamless handoff. If zero-downtime mobility across a Proxmox cluster matters, that favors a VM.
Backups. Both back up the same way through Proxmox — vzdump handles VMs and containers alike, and so does Proxmox Backup Server. There’s no penalty either way; the backup and restore guide applies to both guest types.
Kernel control. Need a specific kernel version, a custom module, or a kernel parameter? That’s a VM, because a container is locked to the host’s kernel. Workloads that load kernel modules (some VPNs, some storage tools) usually want a VM.
Snapshots. Both support snapshots, though the mechanism depends on the underlying storage. On ZFS or LVM-thin, both VM and container snapshots are quick and cheap.
How to choose
Here’s the decision boiled down. Start with the hard constraints, then optimize.
Reach for a VM when
- The OS isn't Linux (Windows, BSD, appliances) — this is non-negotiable
- The workload is untrusted, internet-facing, or multi-tenant and needs strong isolation
- You need a custom kernel, kernel modules, or a nested hypervisor
- You want true zero-downtime live migration across cluster nodes
- You're running Docker and want the supported, low-drama setup
Reach for an LXC container when
- It's a Linux service and you trust the workload
- You want high density — many small services on one host
- Fast start-up and low memory overhead matter
- You're running internal infrastructure: DNS, reverse proxy, monitoring, small web apps
- You don't need a separate kernel or non-Linux OS
If you’re genuinely on the fence for a trusted internal Linux service, default to an unprivileged container for the efficiency, and only promote it to a VM if you later hit a wall — a kernel requirement, an isolation concern, or a migration need. Going container-first and upgrading when necessary wastes fewer resources than running everything as a VM out of habit.
The bottom line
A VM brings its own kernel: it runs any OS, isolates strongly, and migrates live, at the cost of a fixed overhead per guest. A container shares the host kernel: it’s fast, light, and dense, but it’s Linux-only and leans on the kernel for isolation. Windows always means a VM. Trusted Linux services usually mean an unprivileged container. Most real deployments run both.
If you’re just getting your host set up, start with the bare-metal Proxmox VE install, then plan storage with the LVM vs LVM-Thin vs ZFS guide. And if you’re still comparing platforms before committing, the Proxmox VE vs VMware ESXi comparison puts this in a wider context. For more walkthroughs, browse the Proxmox guides.