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.
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
| Service | Docker-based? | Where it goes | Why |
|---|---|---|---|
| Jellyfin | Yes | Docker VM | Runs as a container, shares the VM with everything else |
| Paperless-ngx | Yes | Docker VM | Same VM, same compose stack |
| Mealie | Yes | Docker VM | Same VM |
| Syncthing | Yes | Docker VM | Same VM |
| Vaultwarden | Yes | Docker VM | Same VM |
| Uptime Kuma | Yes | Docker VM | Same VM |
| Immich | Yes | Docker VM | Same VM; heavier on CPU during ML indexing but still just another container |
| Pi-hole / AdGuard Home | Yes (this site’s setup) | Docker VM | Runs fine as a container; see the Pi-hole vs AdGuard guide |
| Authelia | Yes | Docker VM | Same VM as NPM, which it sits in front of |
| Nginx Proxy Manager | Yes | Docker VM | Same VM |
| Technitium DNS | No | Standalone LXC | Native install, no Docker dependency, needs to survive Docker VM downtime |
| Tailscale subnet router | No | Standalone LXC | Single lightweight process, no reason to spend VM overhead on it |
| Home Assistant OS | No (ships as an appliance image) | VM | HAOS is a full OS image with its own update/supervisor system, not something you containerize yourself |
| pfSense / OPNsense | No | VM | A full routing OS; needs its own network stack and often PCI NIC passthrough |
| A standalone Postgres or MariaDB instance | No | LXC | Lightweight, native package install, no Docker overhead needed for a single DB |
| A Minecraft or game server (Java, no Docker) | No | LXC | Runs as a native process; LXC gives it dedicated CPU/RAM without VM overhead |
| Windows-only software | No | VM | LXC is Linux-only, full stop |
| Docker Swarm or Kubernetes nodes | Yes, but… | VM | Overlay 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
| Workload | Recommended type | RAM | Notes |
|---|---|---|---|
| Docker VM (10-15 typical services) | VM | 4-8GB | Add 512MB-1GB per heavier service (Immich, Nextcloud) |
| Single native Linux service (DNS, VPN router) | LXC | 256-512MB | Most single-purpose LXC containers barely touch this ceiling |
| Standalone database (no Docker) | LXC | 512MB-1GB | Depends on dataset size and query load |
| Appliance OS (HAOS, pfSense/OPNsense) | VM | 2-4GB | These expect a full machine, budget accordingly |
| Windows VM | VM | 4-8GB minimum | Windows 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/.