Skip to main content
RunBook Academy

Proxmox VEI · FoundationsConcepts

LXC containers vs virtual machines

Intermediate⏱ ~16 min

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

Not yet marked complete on this device.

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

PropertyKVM VMLXC container
Separate kernelYesNo
Hardware-virt isolationYes (VT-x/AMD-V)No
Independent rebootYesNo
Kernel vulnerability exposureGuest kernel onlyHost kernel = container kernel
Density (containers per host)LowerHigher
Boot timeSecondsSub-second
Live migrationYesYes (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, unprivileged toggle (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: 0 because 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

  1. Q1. In Proxmox, what is the default unprivileged setting for new LXC containers?

  2. Q2. A Linux kernel exploit in an LXC container can affect the host.

  3. Q3. Which workload types are appropriate for an LXC container? (Select all that apply.)

Passing score: 75%. Answers are checked in this browser.