Infrastructure

KVM or LXC on Proxmox: when to choose a VM, when to choose a container

A decision guide to stop guessing. Isolation differences, the security consequences of a shared kernel, the Docker-in-LXC trap, AppArmor profiles and privileges, memory footprint compared and a five-question decision grid.

KVM or LXC on Proxmox: when to choose a VM, when to choose a container
Contents (15 sections)
  1. What each technology actually does
  2. KVM: full virtualisation
  3. LXC: native Linux containers
  4. Kernel sharing: benefit and risk
  5. The Docker-in-LXC trap
  6. Privileged vs unprivileged, and AppArmor
  7. Unprivileged (recommended by default)
  8. Privileged (avoid except in exceptional cases)
  9. Memory and CPU footprint: real figures
  10. Vaultwarden (Bitwarden password manager)
  11. Nextcloud (with PHP-FPM + Nginx + OPcache)
  12. PostgreSQL 16 (dedicated instance, shared_buffers 512 MB)
  13. Five-question decision grid
  14. Rules of thumb by type of service
  15. Conclusion

The great strength of Proxmox VE (and incidentally its biggest source of confusion for new users) is that it offers two virtualisation technologies on the same host: KVM virtual machines and LXC Linux containers. On paper, it might look like a matter of taste. In practice, choosing one or the other has direct consequences for the security, density, performance and maintainability of your infrastructure.

This article sets out what each technology actually does, where the real security risks lie (including the classic Docker-in-LXC trap), how to configure an LXC properly, and gives a five-question decision grid so you never have to hesitate again.

What each technology actually does #

KVM: full virtualisation #

KVM (Kernel-based Virtual Machine) creates a virtual machine in the strict sense: each VM has its own Linux kernel (or Windows, or BSD), its own kernel space, its own drivers and its own process table. The Proxmox hypervisor talks to the hardware through the VT-x or AMD-V hardware extensions, and the VM only “sees” virtualised hardware dedicated to it. Isolation is all or nothing: what happens in the VM does not spill over onto the host, barring a critical QEMU/KVM vulnerability (extremely rare and patched immediately).

LXC: native Linux containers #

LXC (Linux Containers) does not create a virtual machine. It creates an isolated environment that shares the Proxmox host's Linux kernel through native kernel mechanisms: namespaces (PID, network, mount, user, UTS, IPC) and cgroups. The container has its own process table, its own virtual network interfaces and its own file system. But when a process in the container makes a system call, it is the host's kernel that answers.

Comparative diagram of the anatomy of a KVM VM (dedicated guest kernel, QEMU hypervisor, virtualised hardware) and an LXC container (sharing the host kernel through namespaces and cgroups)
On the left, the KVM VM with its own guest kernel. On the right, the LXC sharing the host's kernel through namespaces and cgroups.

Kernel sharing: benefit and risk #

Kernel sharing is what makes LXC containers so light. No second OS to boot, no RAM reserved for a guest kernel, no hardware virtualisation overhead. A minimal Debian container starts in 2 seconds and uses 50 to 80 MB of RAM at idle. On a 32 GB host, you can easily run 30 independent services in 30 separate LXC containers.

The Docker-in-LXC trap #

This is probably the most widespread bad practice in the hobbyist Proxmox world: create a Debian LXC, install Docker in it, then run the whole application stack with Docker Compose. Technically, it works. Officially, it is neither supported nor recommended by the Proxmox developers.

Why? Because you then stack two layers of kernel sharing (LXC + Docker), which multiplies the escape routes. On top of that, Docker needs Linux capabilities that unprivileged LXC containers do not grant: so you either use a privileged LXC (a bad idea for security), enable lxc.cap.keep settings that widen the attack surface, or resort to fuse-overlayfs, which degrades I/O performance.

Privileged vs unprivileged, and AppArmor #

  • The container's root (UID 0) is mapped to an unprivileged UID on the host (typically 100000).
  • An escape to the host grants no real privileges.
  • A restrictive AppArmor profile is applied automatically.
  • Limitation: some unusual mounts (NFS root, FUSE) need extra configuration.

Privileged (avoid except in exceptional cases) #

  • The container's root stays UID 0 on the host.
  • A vulnerability in a service running as root in the LXC gives direct root control of the host.
  • Reserve it for system containers where you control 100% of the code and accept the risk.
  • Never use it to host a public application exposed to the internet.
Bash
# Check the mode of an existing LXC (excerpt from /etc/pve/lxc/100.conf)
cat /etc/pve/lxc/100.conf | grep -E 'unprivileged|features'

# Expected output for an unprivileged container:
# unprivileged: 1
# features: nesting=0

Memory and CPU footprint: real figures #

Theoretical comparisons stay abstract. Here are some real measurements taken on a Proxmox 8 host with Debian 12 as the guest, at idle after all services had fully started.

Vaultwarden (Bitwarden password manager) #

  • Unprivileged Debian LXC: 80 to 130 MB of RAM, 0.1% CPU at idle. Starts in 3 seconds.
  • Debian KVM VM: 480 to 600 MB of RAM (350 of it for the guest kernel and systemd), 0.3% CPU. Starts in 25 seconds.

Nextcloud (with PHP-FPM + Nginx + OPcache) #

  • Unprivileged LXC: 250 to 400 MB of RAM at idle, rising to 1.2 GB under load with 10 simultaneous users.
  • KVM VM: 700 MB to 1 GB of RAM at idle, 1.8 GB under the same load.

PostgreSQL 16 (dedicated instance, shared_buffers 512 MB) #

  • LXC: 550 to 700 MB of RAM. But weak isolation: avoid it for a critical multi-tenant Postgres.
  • KVM VM: 1.1 to 1.3 GB of RAM. Full isolation, recommended for production.
Density comparison on the same 32 GB Proxmox server: 6 KVM VMs on the left, 25 LXC containers on the right, illustrating the difference in memory footprint
On the same 32 GB host, you can comfortably fit 6 KVM VMs or 25 well-sized LXC containers. The choice directly determines application density.

Five-question decision grid #

  1. Will the service handle critical data or be exposed to the internet? → KVM VM (strong isolation).
  2. Do you need to run Docker, Kubernetes, or an OS other than Linux? → KVM VM, no alternative.
  3. Is the service a simple Linux daemon, under your control, with a small memory footprint? → Unprivileged LXC.
  4. Are you trying to maximise density (20+ services on one host)? → Unprivileged LXC, accepting the kernel risk.
  5. Will the service need hardware passthrough (GPU, USB, PCIe card)? → KVM VM, the only mode that supports it properly.

Rules of thumb by type of service #

  • Production database (Postgres, MySQL, MongoDB): dedicated KVM VM.
  • Reverse proxy / WAF (Nginx, Traefik, Caddy): unprivileged LXC, or a VM if it sits directly in front of the internet.
  • Stateless web application (Nextcloud, Vaultwarden, BookStack, Outline): unprivileged LXC.
  • Infrastructure network services (DNS, DHCP, RADIUS): unprivileged LXC.
  • Media and transcoding (Jellyfin, Plex with GPU hardware acceleration): KVM VM with passthrough.
  • Critical home automation (Home Assistant with a USB Zigbee stick): KVM VM with USB passthrough.
  • Development or test environment that needs strong isolation: disposable KVM VM.
  • Anything that needs Docker: KVM VM, never LXC.

Conclusion #

KVM and LXC are not competitors: they complement each other. A well-designed Proxmox host typically mixes a few heavy VMs (databases, Docker services, critical platforms) with a majority of unprivileged LXC containers for every lightweight Linux daemon you control. It is this duality, and the ease with which Proxmox lets you switch from one to the other, that puts it ahead of the competition for building a sovereign private cloud.

Once you have chosen the right technology for each service, the next priority is backups, which forgive no architecture mistakes. The PBS guide explains how to protect the whole fleet, VMs and LXC containers alike, with deduplication, multi-level retention and resistance to ransomware.

About
01/Read nextThree articles

Related articles

Infrastructure

Exploit foundries: your firewall has become the front line

Two undergraduates in Changsha ran an automated pipeline that decrypts firmware, decompiles it through thousands of calls, forms hypotheses about vulnerabilities, writes the exploit and tests it in a lab, in a loop, day and night. More than a dozen unknown vulnerabilities in a month on network devices, some fifty organisations targeted, thirteen collection agents on a scheduled task. What this means for an SME's inventory.

cybersecurityvulnerability
Infrastructure

Intermittent SERVFAIL: the orphaned DS record that broke 15% of lookups

A CI pipeline failing intermittently, two different error messages, an obvious suspect that had nothing to do with it, and an invisible cause: a DNSSEC record still published at the parent while the zone was no longer signed. Post-mortem of a nasty DNS failure, with the method that finally settled it.

dnssecdns
Infrastructure

Patching 36 servers without unattended-upgrades

There are three doctrines: do nothing, automate everything blindly, or look first and then decide. We removed unattended-upgrades from the whole fleet and dismantled our own automatic patching with Ansible, in favour of a “visibility first” doctrine backed by PatchMon. Why, how, and the routine that goes with it.

patch managementpatchmon

What next

Infrastructure that is managed and monitored day and night?

Bastion, SIEM, patches applied on purpose, tested backups: what we apply for our clients. First conversation free.

Discuss your project

Reply within 24 working hours, from one of the two founders. Or by phone: +33 7 59 96 14 99.