Proxmox Docker LXC vs VM: Which Should You Use in 2026?

Short answer: New to Proxmox? Run Docker in a small Linux VM. It has its own kernel, and Proxmox's container docs call nesting containers inside a QEMU VM "a recommended practice" for use cases needing maximum isolation and live migration. Docker in an unprivileged LXC is also possible with the nesting and keyctl features, but it's tied to the host's kernel.

If you read other guides on "proxmox docker lxc vs vm", check which Proxmox version they were written for. This guide is written for Proxmox VE 9.2, the current release on the official downloads page (checked 12 November 2026), and the commands below were checked against the official Proxmox VE and Docker documentation. They were not run on a test host for this guide, so read each step before you paste it.

What's actually different

A VM (KVM/QEMU) emulates a whole computer and boots its own kernel. An LXC container shares the Proxmox host's Linux kernel and is isolated with namespaces, cgroups, AppArmor and seccomp (Proxmox VE: Linux Container).

Docker is itself a container runtime. In a VM, Docker runs on the guest's own kernel, just like on a normal server. In an LXC, Docker creates containers inside a container, so it needs extra permissions from the host.

What Proxmox officially says

The current Proxmox VE container chapter says:

While running lightweight “Application Containers” directly offers significant advantages over a full VM, for use cases demanding maximum isolation and the ability to live-migrate, nesting containers inside a Proxmox QEMU VM remains a recommended practice. — Proxmox VE Administration Guide, Linux Container

That line is about Proxmox's own OCI application containers, but the reasoning carries over to Docker.

The keyctl feature in the pct manual is marked "For unprivileged containers only" and described as "required to use docker inside a container", and the same entry adds: "Essentially, you can choose between running systemd-networkd or docker." The nesting option "will expose procfs and sysfs contents of the host to the guest."

So Proxmox documents the settings Docker in LXC needs, and it's plain about the trade-offs. Its container docs also say: "In general, full virtual machines provide better isolation."

LXC vs VM for Docker at a glance

Docker in an unprivileged LXC Docker in a VM
Kernel Shares the Proxmox host kernel Own guest kernel
Extra Proxmox settings nesting=1 and keyctl=1 features None beyond a normal VM
Isolation Namespaces, cgroups, AppArmor, UID mapping Hypervisor boundary
Live migration No; offline or restart migration only Yes, when prerequisites are met
Host updates Kernel/AppArmor changes can affect Docker Guest kernel is independent
Docker install docs Not covered by Docker's docs; needs Proxmox's nesting and keyctl features Work unchanged
Resource overhead Lower (no guest kernel) Higher (full guest OS)
Best for Trusted, low-stakes homelab stacks Beginners, exposed or important services

The Proxmox docs describe LXC as a way to get VM-like benefits "without the additional overhead". This guide doesn't give overhead figures; the Proxmox docs cited here don't include any.

Why host updates matter for Docker in LXC

Because an LXC shares the host kernel, a host upgrade can change Docker's behaviour inside it. The Proxmox VE 9.0 release notes listed "a known issue with nested containerization (e.g., Docker inside an LXC container)", tracked as bug #6538. On 21 July 2025, a Proxmox staff member wrote on the official forum: "A new pve-container package with version 6.0.3 has just been uploaded, it contains a fix to generates [sic] the relevant mqueue apparmor rule by default." The same post adds that "enabling keyctl and other features might still be required and is not considered a bug" (checked 12 November 2026). Docker in a VM runs on the guest's own kernel, so host-side kernel and AppArmor changes like this one don't reach it directly.

Steps: run Docker in a VM (recommended default)

Example IDs and sizes are placeholders. Change 200, local-lvm, vmbr0 and the ISO filename to match your host.

  1. Upload a Debian 13 ISO. Debian 13 "Trixie" is listed as supported in Docker's Debian install guide. Put the netinst ISO from debian.org on your ISO storage (for example local).
  2. Create the VM on the Proxmox host shell (qm manual):
    qm create 200 --name docker-vm --ostype l26 --cores 2 --memory 4096 \
      --scsihw virtio-scsi-single --scsi0 local-lvm:32 \
      --net0 virtio,bridge=vmbr0 \
      --cdrom local:iso/<debian-13-netinst-file>.iso \
      --boot 'order=scsi0;ide2' --agent enabled=1
    qm start 200
    
    local-lvm:32 uses the documented STORAGE_ID:SIZE_IN_GiB syntax to create a 32 GiB disk.
  3. Install Debian from the VM's Console in the web UI. Choose a minimal install with the SSH server. Debian's installer guide says that if you leave the root password empty, root is disabled and your first user gets sudo. If you set a root password instead, run the commands below as root and leave out sudo.
  4. Install the QEMU guest agent inside the VM. Proxmox says the package "is usually named qemu-guest-agent" (QEMU Guest Agent):
    sudo apt install qemu-guest-agent
    
    Proxmox's docs also say to "make sure it is running". Then check it from the host: qm guest cmd 200 ping.
  5. Add Docker's apt repository, exactly as in Docker's Debian guide:
    sudo apt update
    sudo apt install ca-certificates curl
    sudo install -m 0755 -d /etc/apt/keyrings
    sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
    sudo chmod a+r /etc/apt/keyrings/docker.asc
    sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
    Types: deb
    URIs: https://download.docker.com/linux/debian
    Suites: $(. /etc/os-release && echo "$VERSION_CODENAME")
    Components: stable
    Architectures: $(dpkg --print-architecture)
    Signed-By: /etc/apt/keyrings/docker.asc
    EOF
    sudo apt update
    
  6. Install Docker Engine and Compose:
    sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
    
  7. Test it: sudo docker run hello-world. Docker's docs say this "downloads a test image and runs it in a container."

Steps: run Docker in an unprivileged LXC

Use this when the stack is trusted, internal, and easy to rebuild.

  1. Get a Debian template (pveam manual):
    pveam update
    pveam available --section system
    pveam download local <debian-13-standard template name from the list>
    
  2. Create the container with Docker's features turned on (pct manual). Set --unprivileged 1 explicitly:
    pct create 210 local:vztmpl/<template-file> \
      --hostname docker-ct --unprivileged 1 --features nesting=1,keyctl=1 \
      --cores 2 --memory 2048 --rootfs local-lvm:16 \
      --net0 name=eth0,bridge=vmbr0,ip=dhcp
    pct start 210
    pct enter 210
    
    On an existing container, run pct set 210 --features nesting=1,keyctl=1, then pct reboot 210.
  3. Install Docker with the same commands as VM steps 5 and 6. You're root inside the container, so you can drop sudo.
  4. Test it: docker run hello-world, then run docker info to see which storage driver Docker chose.
  5. Confirm the config from the host with pct config 210. The output should include unprivileged: 1 and a features: line containing keyctl=1 and nesting=1.

Can I pass a GPU to Docker in LXC or a VM?

Proxmox documents a different route for each. PCI(e) passthrough hands a whole PCI(e) device, such as a GPU, to a VM, and the dev[n] option passes a host device into a container. This section covers only the Proxmox side. Getting the GPU from the VM or container into your Docker containers isn't covered by the docs cited here, so check Docker's own documentation for that step. The Proxmox docs quoted here were checked on 12 November 2026. The commands were checked against those docs only and were not run on a test host.

VM: the whole device moves to the guest. Proxmox's PCI(e) passthrough docs describe passthrough as "a mechanism to give a virtual machine control over a PCI device from the host" and warn: "if you pass through a device to a virtual machine, you cannot use that device anymore on the host or in any other VM." It also affects migration: "PCI or USB devices that are passed through currently block live-migration" (live migration requirements).

The host requirements the docs list:

  1. Hardware that supports "IOMMU (I/O Memory Management Unit) interrupt remapping", in both the CPU and the motherboard. The docs say Intel systems with VT-d and AMD systems with AMD-Vi generally support this, but "It is not guaranteed that everything will work out of the box".
  2. IOMMU support turned on in the BIOS/UEFI. Separately, the docs say the Linux kernel enables IOMMU by default with AMD CPUs, and with Intel CPUs on kernels 6.8 or newer. On older kernels, Intel CPUs need intel_iommu=on on the kernel command line.
  3. The vfio, vfio_iommu_type1 and vfio_pci modules listed in a file under /etc/modules-load.d/, then update-initramfs -u -k all and a reboot.
  4. The device in its own IOMMU group. Check with pvesh get /nodes/{nodename}/hardware/pci --pci-class-blacklist "". The docs say sharing a group with the device's own functions (such as a GPU's HDMI audio) is fine.

Proxmox VE tries to make the device unavailable to the host automatically. If that doesn't work, the docs give two fixes: pass the device IDs to the vfio-pci module options, or blacklist the host driver. Once the device is free, its entry in lspci -nnk should include Kernel driver in use: vfio-pci; the docs say a missing "in use" line also means it's ready. Then add it with qm set 200 --hostpci0 <PCI address> (qm manual). For GPUs, the docs say "the best compatibility is reached when using q35 as machine type, OVMF (UEFI for VMs) instead of SeaBIOS and PCIe instead of PCI", and add that OVMF needs a GPU with a UEFI-capable ROM; otherwise, use SeaBIOS. The example VM above doesn't set any of these, so decide before you create it.

LXC: a host device passed into the container. Containers "use the kernel of the host system that they run on" (Linux Container). That suggests a device passed into a container is still handled by the host's kernel and drivers, not a guest kernel. This is an inference from the shared-kernel design, not a Proxmox statement. The pct manual documents dev[n], "Device to pass through to the container", with optional uid, gid, mode and deny-write settings. For example: pct set 210 --dev0 <host-device-path>,gid=<gid>. According to the release notes, the API and CLI have supported this since Proxmox VE 8.1, and the GUI since 8.2. The pct docs cited here don't list any IOMMU setup for dev[n].

What the Proxmox docs cited here don't cover: whether the host can still use a device after it's passed to a container, and whether several containers can share one GPU. If you need either, test it on your own hardware before you rely on it.

Checklist before you commit

  • Decided which one you need: a VM for exposed, important or untrusted services, or an LXC for trusted, internal, easy-to-rebuild stacks
  • If LXC: unprivileged, with nesting=1 and keyctl=1, and restarted after any feature change
  • Not running Docker in a privileged container just to make an error go away
  • Docker installed from Docker's official apt repository, and hello-world works
  • Docker volumes and app data covered by a backup, and the backup restored once as a test
  • Extra LXC mount points checked: the backup flag only applies to volume mount points, and "The contents of bind mount points are not backed up when using vzdump" (pct docs)
  • Docker VM: qemu-guest-agent installed and qm guest cmd <vmid> ping answers
  • Release notes read before upgrading a Proxmox host that runs Docker in LXC
  • Firewall rules inside the Docker host made with iptables/ip6tables (not nft) and added to the DOCKER-USER chain. Docker's docs warn: "If you use ufw or firewalld to manage firewall settings, be aware that when you expose container ports using Docker, these ports bypass your firewall rules." They add: "Make sure that any firewall rulesets you use are created with iptables or ip6tables, and that you add them to the DOCKER-USER chain" (Docker docs: Firewall limitations)

Where Proxmox VE 9's OCI containers fit

Proxmox VE 9.1 added the ability to create LXC containers from OCI images (roadmap). The current docs say "running application containers in Proxmox VE is currently considered a technology preview." Compose-style multi-container apps appear on the roadmap as future work, not a shipped feature. For now, Docker Compose in a VM is still the sensible home for multi-container stacks.

FAQ

Can you run Docker in a Proxmox LXC container?

Yes. Use an unprivileged container, enable the nesting and keyctl features, and restart it. Proxmox's pct manual says keyctl is "required to use docker inside a container."

Is a VM or LXC better for Docker on Proxmox?

For most beginners, a VM. Proxmox's container docs say nesting containers inside a QEMU VM "remains a recommended practice" for use cases that need maximum isolation and live migration. LXC is lighter but shares the host kernel.

Can Proxmox LXC containers live-migrate?

No. Proxmox's docs say running containers cannot be live-migrated. A restart migration shuts the container down, moves it, and starts it on the target node. VMs can live-migrate when the prerequisites are met.

Should Docker run in a privileged LXC container?

Usually not. In an unprivileged container, root is mapped to an unprivileged user on the host, so most container escapes only reach that user. Proxmox says privileged containers should only be used in trusted environments.

Do Proxmox VE 9 OCI containers replace Docker?

Not yet. Proxmox VE 9 can create containers from OCI images, but its docs call application containers a technology preview. Compose-style multi-container support is listed on the roadmap as future work.

Sources

Sources checked 12 November 2026.

Further reading (not relied on for any claim above):

Corrections

If something on this page is wrong, see Corrections.