Blog
ENPL

Proxmox VM or LXC — when to pick which

Proxmox hosts 12 machines for me — a mix of VMs and LXCs. Showing the rule for when to use Linux containers vs full virtualization, with concrete examples.

·4 min read
Proxmox VM or LXC — when to pick which

Proxmox VE offers two isolation types: full VMs and Linux containers (LXC). Most people only use VMs because they're "safer". I run ~60% LXC, ~40% VM. Here's the rule for when to pick which.

Quick characteristics

VMLXC
Isolationfull (KVM)namespace + cgroups
Boot time~30s~2s
RAM overhead+200-500MB+5-20MB
Storage overheadlarge (qcow2)small (rootfs)
Live migrationyesyes
Kernelownhost's
Securitystrongweaker (CVE escapes)

LXC isn't Docker, it's a "lightweight VM" with its own init, users, files. More like BSD jails than Docker.

Rule: when LXC

LXC for:

  • Single-purpose services (one daemon, small stack): Pi-hole, Vikunja, single-DB
  • Linux-only self-hosted apps: Nextcloud, Jellyfin, Bitwarden
  • Test environments: setup/teardown in 30s
  • Anything that idles at a few MB of RAM

LXC NOT for:

  • Anything with a different kernel from host (Windows, BSD, ARM on x86 host)
  • Workloads with exposed root (root in LXC + escape = root on host)
  • Anything requiring fully isolated for compliance

Rule: when VM

VM for:

  • Other OSes: Windows for testing, BSD as a router (pfSense, OPNsense)
  • Kernel modules: ZFS-on-Linux, eBPF probes, custom kernel
  • Strong isolation: services that potentially handle untrusted data
  • Hardware passthrough: GPU passthrough, USB devices

Concrete examples from my setup

LXC: Pi-hole

Pi-hole uses ~50MB RAM idle. A VM would need 512MB just for overhead. LXC = pct create 100 ubuntu-22.04 --rootfs local-zfs:8 --memory 256 and it runs.

LXC: Vikunja + Postgres

Two LXCs in one zone. Vikunja listens on 3456, Postgres on 5432, they talk over an internal network. Together ~500MB RAM, a VM-each setup would chew 1.5GB.

VM: pfSense

Routing must run FreeBSD. Plus I use packages like Suricata which need specific kernel modules. VM is the only option.

VM: Home Assistant OS

HA OS ships a whole distribution with a pre-configured addon system. As LXC you'd assemble by hand. VM = download .qcow2 from home-assistant.io, import, done.

VM: Jellyfin (with GPU passthrough)

Video transcoding needs a GPU. GPU passthrough into LXC is possible but annoying. VM is the standard flow.

Conversion between LXC and VM

Sometimes you start in one, then want to switch.

LXC → VM: hard. You need migration via tarball + virtual-format conversion. Better to spin a new VM.

VM → LXC: nearly impossible without reinstall. VM has its own kernel and bootloader, LXC inherits.

Rule: plan early. If unsure, start with LXC, easier to up-isolate (spin a new VM) than down-isolate.

ZFS as a bonus

Proxmox loves ZFS. I have my containers/VMs on a ZFS pool with:

  • Snapshots: instant state copy, atomic. zfs snapshot pool/lxc-100@before-update
  • Send/receive: replicate to a second host in half an hour
  • Compression: ~30% less space

ZFS works particularly well in LXC, since the container doesn't need its own file system, it inherits from the host.

Pitfalls

1. LXC unprivileged vs privileged. Default is unprivileged (root in container = mapped to an unprivileged user on host). Safer, but some apps refuse to run. Privileged = more convenient but an escape = full host root.

2. VM backups are big. A 50GB VM snapshot = 50GB backup. LXC with the same data = 5GB backup. ZFS dedup helps, not always.

3. LXC live migration. Works, but needs shared storage or replication. VMs handle this better.

4. LXC kernel = host kernel. Updating the host = restart all LXCs. Updating a VM kernel = zero downtime on the host. Plan downtime windows.

Numbers from my homelab

  • 4 VMs: pfSense, HA OS, Jellyfin (GPU PT), Windows Server (ad hoc)
  • 8 LXCs: Pi-hole×2, Vikunja, Postgres, Bitwarden, Nextcloud, Obsidian-sync, dev-test
  • Total usage: ~12GB RAM out of 64GB available
  • Average boot LXC: 1.8s, VM: 28s

LXC gives me 8x more services on the same hardware. Without functional compromises for most things.


Start with LXC. Escalate to VM only when you have a concrete reason (different OS, kernel modules, isolation, hardware). Most self-hosted apps don't need a VM, and your RAM will thank you.