Proxmox VEI · FoundationsConcepts
LXC containers vs virtual machines
What you'll learn
- Explain the security boundary between LXC and KVM
- Choose between privileged and unprivileged containers based on threat model
- Map namespaces and cgroups to observable behaviour
- Know when not to use a container
Prerequisites
Verified against Proxmox VE 9.2.4 · Proxmox Backup Server 4.2.5 · Ceph Squid / Tentacle · Debian 13 (Trixie) · Linux kernel 7.0 (PVE 9.2 default) · 2026-08-07
Why this matters in production
Misclassifying a workload as “a container is fine” is one of the most consequential mistakes a Proxmox administrator can make. The container will appear to work — until the day a kernel vulnerability or a misconfigured capability lets a guest process read a host file or kill a host process.
Mental model
A container is a process tree on the host, isolated by:
- Namespaces — different views of system resources (PID, network, mount, UTS, IPC, user, cgroup).
- cgroups — quotas and accounting for CPU, memory, I/O, PIDs.
There is no separate kernel. There is no hardware-virtualisation boundary. The container’s processes are the host’s processes; they just see a slice of the system.
flowchart TB
subgraph CONTAINER[LXC container]
C1[Container processes]
C2[Namespace view: PID 1..N]
C3[Mount view: own /]
end
subgraph HOST[Host]
H1[Host kernel]
H2[cgroup hierarchy]
H3[All host processes]
end
C1 --> H1
C1 --> H2
H2 --> H3
Security boundary: a clear comparison
| Property | KVM VM | LXC container |
|---|---|---|
| Separate kernel | Yes | No |
| Hardware-virt isolation | Yes (VT-x/AMD-V) | No |
| Independent reboot | Yes | No |
| Kernel vulnerability exposure | Guest kernel only | Host kernel = container kernel |
| Density (containers per host) | Lower | Higher |
| Boot time | Seconds | Sub-second |
| Live migration | Yes | Yes (offline or online, depending on workload) |
Privileged vs unprivileged
Proxmox distinguishes:
- Unprivileged container (
unprivileged: 1, the default in new templates): UID 0 inside the container maps to a non-root UID on the host. The container cannot directly write to host-owned files; a kernel vulnerability is harder to escalate. - Privileged container (
unprivileged: 0): UID 0 inside the container is UID 0 on the host. Almost no isolation from the host filesystem. Required for some legacy software and Docker-in-LXC setups, but a significant security trade-off.
flowchart LR
subgraph UP[Unprivileged]
UC[UID 0 in CT] -->|maps to| UH[UID 100000 on host]
end
subgraph PR[Privileged]
PC[UID 0 in CT] -->|is| PH[UID 0 on host]
end
GUI walkthrough
Container creation (Create → CT) presents:
- General tab: hostname, password (or SSH key).
- Template tab: choose from downloaded templates (Debian, Ubuntu, Rocky, Alma, Alpine, Fedora, openSUSE, Arch, CentOS, …).
- Disks tab: rootfs size and storage backend.
- CPU tab: cores, CPU limit/weight.
- Memory tab: RAM, swap.
- Network tab: bridge, VLAN tag, IP/CIDR, gateway.
- DNS tab: DNS servers and search domain.
- Features tab: nesting, FUSE, NFS,
unprivilegedtoggle (default on).
CLI walkthrough
pct list
pct config 200
pct set 200 -features nesting=1
When to use which
Use a container when:
- The workload is a Linux service with no kernel-version sensitivity.
- You need fast provisioning, low overhead, or very high density.
- The workload is trusted (it is your code, not untrusted input).
- The cluster does not have spare RAM for separate kernels per workload.
Use a VM when:
- The workload is Windows or any non-Linux OS.
- The workload needs a different kernel version or kernel modules (e.g., WireGuard kernel module newer than the host).
- The workload is untrusted or runs arbitrary user code.
- The workload must survive a host kernel upgrade without modification.
- Compliance requires a separate-kernel boundary.
Production considerations
Common mistakes
- Setting
unprivileged: 0because a tutorial said so. Default to unprivileged. - Running Docker inside a privileged container. Use a VM for true Docker isolation, or accept the trade-off of an unprivileged container with nesting.
- Assuming a container survives a host kernel upgrade. It does not — the guest kernel is the host kernel.
Key takeaways
- LXC isolates with namespaces and cgroups; it does not provide a separate-kernel boundary.
- Unprivileged is the default for good reason.
- Use containers for trusted Linux services; use VMs for anything that needs stronger isolation.
Knowledge check
Knowledge check · 3 questions
Q1. In Proxmox, what is the default unprivileged setting for new LXC containers?
Q2. A Linux kernel exploit in an LXC container can affect the host.
Q3. Which workload types are appropriate for an LXC container? (Select all that apply.)
Passing score: 75%. Answers are checked in this browser.