← All Guides
beginner

LXC vs VM in Proxmox: When to Use Each (With Real Examples)

A reference list of 18 real homelab services and whether each one belongs in a Proxmox LXC container or a VM, plus the mistake most beginners make with Docker sprawl.

Budget Homelab ·
proxmoxlxcvirtualizationhow-to

If you’ve read the Proxmox VM vs LXC guide, you already know the conceptual split: VMs for full isolation and Docker, LXC for lightweight native Linux services. That guide explains why. This one is the reference list I wish existed when I started: an actual lookup table of real homelab services and which one I’d pick for each, plus the one pattern that trips up almost every beginner.

The pattern beginners get wrong

Here it is, up front: you don’t create a new VM or LXC container for every service.

I see this constantly in homelab forums. Someone spins up a VM for Jellyfin, another VM for Vaultwarden, a third for Uptime Kuma, and within a month they’re running eight VMs on a machine that could handle all of it in one. Every VM carries its own OS overhead: RAM allocation, disk footprint, patching, monitoring. Multiply that by eight and you’ve turned a mini PC into a resource-management chore.

The actual pattern that works: one Docker VM hosts every Docker-based service. On my node (192.168.1.10), a single Ubuntu 24.04 VM runs Jellyfin, Paperless-ngx, Mealie, Syncthing, Authelia, and NPM, all as Docker containers inside that one VM, all managed with docker compose. Adding a new service means adding a new compose block, not provisioning new infrastructure. LXC is reserved for the handful of things that don’t run in Docker at all: Technitium DNS at 192.168.1.102, and a Tailscale subnet router. Both are simple enough that full VM isolation would be wasted overhead.

That’s the real decision, and it’s simpler than most guides make it sound: is this thing going in Docker? Then it goes in the Docker VM. Is it a standalone native service? Then it’s a candidate for its own LXC container.

Real examples: what goes where

ServiceDocker-based?Where it goesWhy
JellyfinYesDocker VMRuns as a container, shares the VM with everything else
Paperless-ngxYesDocker VMSame VM, same compose stack
MealieYesDocker VMSame VM
SyncthingYesDocker VMSame VM
VaultwardenYesDocker VMSame VM
Uptime KumaYesDocker VMSame VM
ImmichYesDocker VMSame VM; heavier on CPU during ML indexing but still just another container
Pi-hole / AdGuard HomeYes (this site’s setup)Docker VMRuns fine as a container; see the Pi-hole vs AdGuard guide
AutheliaYesDocker VMSame VM as NPM, which it sits in front of
Nginx Proxy ManagerYesDocker VMSame VM
Technitium DNSNoStandalone LXCNative install, no Docker dependency, needs to survive Docker VM downtime
Tailscale subnet routerNoStandalone LXCSingle lightweight process, no reason to spend VM overhead on it
Home Assistant OSNo (ships as an appliance image)VMHAOS is a full OS image with its own update/supervisor system, not something you containerize yourself
pfSense / OPNsenseNoVMA full routing OS; needs its own network stack and often PCI NIC passthrough
A standalone Postgres or MariaDB instanceNoLXCLightweight, native package install, no Docker overhead needed for a single DB
A Minecraft or game server (Java, no Docker)NoLXCRuns as a native process; LXC gives it dedicated CPU/RAM without VM overhead
Windows-only softwareNoVMLXC is Linux-only, full stop
Docker Swarm or Kubernetes nodesYes, but…VMOverlay networking for Swarm/K8s is unreliable inside LXC; use VMs for cluster nodes

The pattern holds across all eighteen: if it’s Docker, it joins the existing Docker VM. If it’s not, and it’s a single lightweight Linux process, it gets its own LXC container. If it’s an appliance image, needs Windows, or needs a real network stack of its own (a router OS, a cluster node), it gets a VM.

Three real decisions, worked through

“I want to add a fourth Docker service.” Don’t create anything new. SSH into the existing Docker VM, add a service block to the compose file (or a new compose file in its own directory), and docker compose up -d. This is true whether it’s your 2nd service or your 20th: the VM doesn’t get more expensive to run per-service, only the RAM and CPU the containers themselves consume does.

“I want a second DNS resolver as a backup.” This is a real LXC case, not a Docker one. A second lightweight LXC container running Technitium or Pi-hole natively (not in Docker) gives you DNS redundancy that survives even a full Docker VM outage. Two DNS LXC containers at different static IPs, configured as primary/secondary on your router, is a genuinely useful five-minute build.

“I want to try Home Assistant.” This is the case that trips people up, because HAOS looks like it should be a lightweight container-friendly thing, and it isn’t. Home Assistant OS ships as a complete appliance image with its own supervisor, add-on store, and update mechanism. It expects to own the whole VM. Trying to wedge it into LXC or run “Home Assistant Container” (the stripped-down Docker image) inside your existing Docker VM works for basic automations but loses the add-on ecosystem that makes HAOS worth using in the first place. If you want the full HAOS experience, give it its own small VM (2 cores, 4GB RAM is plenty) rather than trying to force it to share.

Resource sizing cheat sheet

WorkloadRecommended typeRAMNotes
Docker VM (10-15 typical services)VM4-8GBAdd 512MB-1GB per heavier service (Immich, Nextcloud)
Single native Linux service (DNS, VPN router)LXC256-512MBMost single-purpose LXC containers barely touch this ceiling
Standalone database (no Docker)LXC512MB-1GBDepends on dataset size and query load
Appliance OS (HAOS, pfSense/OPNsense)VM2-4GBThese expect a full machine, budget accordingly
Windows VMVM4-8GB minimumWindows itself is the overhead here, not the workload

On an N100 mini PC with 16GB total RAM, that’s one 6-8GB Docker VM plus 4-6 small LXC containers (DNS, subnet router, maybe a second DNS for redundancy) with headroom left over. That’s the actual ceiling most budget homelabs hit long before the hardware runs out: organization, not raw resources.

Passthrough: the one place the mechanics really diverge

For most decisions in this guide, the choice is simple: Docker goes to the VM, single native services go to LXC. Device passthrough is the exception where the how matters as much as the what.

VMs pass through hardware at the PCI level (a dedicated GPU, a Coral TPU, a Zigbee USB dongle), which usually requires IOMMU enabled in the BIOS and, for PCI devices, isolating them from the host entirely. That’s real isolation, but it’s also more setup and the device is unavailable to the host or any other guest while the VM has it.

LXC containers can often skip that entirely with a device-node bind mount. An integrated GPU’s render node at /dev/dri, for example, can be mounted straight into a container with no IOMMU configuration at all, and unlike PCI passthrough, the host and other containers can still see the device too. That’s not universal (a dedicated GPU or PCIe card generally still wants proper passthrough), but for the common case of a USB dongle or an onboard device, LXC’s bind-mount approach is the lower-friction path. The Proxmox USB Passthrough guide covers the config-file mechanics for getting a device into an LXC container, since the web UI only supports passthrough for VMs.

The takeaway

Don’t ask “VM or LXC?” per service. Ask it once, for your Docker workload as a whole, and build one right-sized VM for it. Then ask it again only for the small number of services that genuinely don’t belong in that Docker VM: appliance OSes, Windows, cluster nodes, and the couple of native Linux services (DNS, a subnet router) that are worth splitting out for resilience or overhead reasons. Everything else is just another line in a compose file.

For the deeper explanation of why VMs and LXC behave so differently under the hood, see the Proxmox VM vs LXC guide. If you’re setting up Proxmox for the first time, the Proxmox beginner’s guide and the Docker Compose basics guide cover the ground floor. For running Docker inside LXC specifically (rather than the VM approach recommended here), the Proxmox LXC Docker template guide has the two feature flags that make it actually work.

See the full homelab stack at /stack/.