The Container That Isn't a Container
Understanding the difference changes your whole operational model.

Running a growing homelab means making infrastructure decisions you’ll live with for years. As I have been rebuilding my lab over the past few months, Docker was the obvious first choice: container images are easy to stand up, networking ports and dependencies are declared in a compose file, and the ecosystem is enormous. For a handful of services, that model worked cleanly.
As the service count grows, the operational friction accumulates. Backups require protecting data volumes and compose configurations as separate concerns, with different tools for each. Updating a service means a pull-and-redeploy cycle rather than a package update. Migrating a container between hosts runs into subtle differences in network backends, volume paths, and runtime configurations that rarely surface until something actually needs to move.
LXC containers in Proxmox don’t solve every problem, but they match the operational model I already had for the rest of my infrastructure: back up the whole thing, update it like a Linux server, and migrate it between nodes when needed. The framing that helped me was simple: LXC containers are persistent, full-system Linux environments that share the host kernel. Not Docker. Not VMs. Something with its own trade-off profile that fits specific scenarios well and others poorly. Understanding where that boundary falls is worth doing before you commit either way.
What Runs Inside
The shared kernel is where Docker and LXC converge. Both share the host kernel rather than running a guest kernel through a hypervisor. That’s their common ground, and also where most comparisons start generating confusion.
The divergence is in scope. Docker containers are designed around a single application or tightly coupled service boundary rather than a full machine environment. The model is one service per container: your Nginx container runs Nginx, your Redis container runs Redis. The container is disposable infrastructure for the application, not a system to administer.
LXC containers are what the Linux Containers project calls “system containers,” meaning full Linux environments with their own init system that run multiple services the way a full OS would. You log into one via the Proxmox console and it feels like SSH-ing into a small server rather than exec-ing into a running process.
The practical difference shows up when you try running multiple services in a single LXC container and it just works, without the compose-file orchestration Docker requires. Whether you should run multiple services together is a separate question, but LXC doesn’t impose Docker’s one-service-per-container model.
| Characteristic | Full VM | LXC Container | Docker (in VM) |
|---|---|---|---|
| Kernel | Own kernel | Shared (host) | Shared (host) |
| Init system | Full systemd | Full systemd | Process only |
| Startup time | 30–60s | 2–5s | 1–3s |
| Idle RAM overhead | 150–200MB | 30–60MB | 10–30MB |
| Host kernel isolation | Full (hypervisor) | Namespace only | Namespace only |
| Proxmox snapshots | Full state | Full state | Volume + compose dependent |
| GPU passthrough | PCIe device | Host driver share | Via VM |
The Isolation Layer
Docker and LXC both rely on Linux namespaces and cgroups for isolation because neither runs a guest kernel. Namespaces (pid, network, mount, uts, ipc, user) partition the environment; cgroups control the resources. Docker manages that boundary automatically as part of its container runtime. LXC exposes the full namespace and cgroup configuration directly, which is why LXC containers look and behave more like VMs even though the underlying isolation mechanism is identical.
What makes this interesting in Proxmox is how thin that isolation layer is compared to a full VM. VMs route system calls through a hypervisor and a guest kernel before reaching hardware. LXC containers reach the host kernel directly with only namespace-level filtering in the path.
Proxmox’s Linux Container documentation covers the architecture in detail. The term “micro VM” gets applied to LXC informally, but the defining distinction is kernel ownership. AWS Firecracker and Kata Containers run guest kernels through lightweight virtualization. LXC shares the host kernel directly. By that definition, LXC is a system container — not a micro VM.
Proxmox treats LXC containers as first-class citizens alongside VMs: same resource allocation panels, same cluster resource tree, same snapshot and backup mechanisms. Snapshot an LXC container and restore it to a new ID, and you get a complete working environment rather than a layer cache.
The Operations Gap
The architectural differences matter less in practice than the operational ones. This is where the homelab use case diverges from the development environment Docker was designed for.
The backup story is where the gap is most concrete. Proxmox Backup Server backs up LXC containers natively as atomic units, covering filesystem state and configuration in a single job. Deduplication is built in and point-in-time restore to a new container ID works cleanly. Docker decomposes persistence across images, compose definitions, environment configuration, and attached volumes. Each piece can be backed up cleanly, but the operational responsibility is distributed across several systems rather than consolidated. You’re maintaining a backup strategy rather than running a backup job.
Updates follow a similar pattern. In an LXC container, updating a service means apt upgrade or the equivalent package manager. State transitions work the same way they would on a bare-metal server. Docker updates mean pulling a new image and redeploying, which is manageable for stateless services but adds coordination overhead for anything with persistent configuration state or data.
Networking is where Docker’s abstractions create the most friction for a homelab. LXC containers get real network interfaces on the host’s bridge, with IP addresses (and MAC addresses, which makes DHCP reservations easy) that are first-class citizens on the local network. Other services reach them the same way they’d reach a physical host. Docker’s default mode is a NAT bridge with port mapping, which adds translation overhead and configuration complexity for service-to-service communication.
Can Docker replicate what LXC does for networking? With --cap-add NET_ADMIN and custom network configurations, largely yes. The honest answer is that LXC’s default mode is the Linux networking model, while Docker’s default mode is an abstraction layer over it. The configuration complexity is the real difference, not a hard capability wall. That abstraction is often useful in development environments where portability and dependency isolation matter more than network citizenship, but it works against you in a homelab where every service is expected to show up on the network like a first-class node.
The Decision in Practice
In practice, the choice between full VMs, LXC containers, and Docker usually comes down to what the workload actually needs.
Full VMs make sense when you need a different kernel, whether that’s Windows or a specific Linux version for driver compatibility. VMs are also the right call when host kernel isolation is a hard requirement, or when you’re running Docker and want clean separation rather than the nesting complexity of running it inside LXC.
LXC containers work well for Linux services with straightforward requirements. This covers most homelab services, from DNS resolvers and reverse proxies to monitoring stacks and self-hosted applications. Startup time advantages over VMs are real, and the resource overhead difference compounds when you’re running a lot of services on hardware that isn’t a dedicated server rack.
Docker inside a VM makes sense when you want the Docker ecosystem specifically and don’t want the nesting complexity of running it inside LXC. Services with complex multi-container networking or first-class Docker support fit this pattern better, and a dedicated VM keeps things cleanly separated.
Docker inside LXC is possible. Proxmox documents the approach for unprivileged containers and it does work. The privilege escalation requirements and security trade-offs make it the least clean option, and I wouldn’t default to it without a specific reason the alternatives don’t fit.
The Overhead Numbers
The resource difference between LXC containers and VMs is real enough to matter at homelab scale. A minimal Debian VM in Proxmox sits around 150–200MB of RAM at idle, carrying the weight of a guest OS kernel, its own memory management, and whatever guest agent processes Proxmox integration requires. An equivalent LXC container running the same workload sits around 30–60MB of baseline overhead. Across twenty services on a machine with 32GB of RAM, that’s meaningful headroom.
CPU overhead follows a similar pattern. VMs route instructions through the hypervisor layer; LXC containers run on the host kernel directly. Hardware virtualization has narrowed the gap considerably over the last several years, but it’s still measurable under sustained load.
The more interesting overhead, for me at least, has been operational. LXC containers start in two to three seconds and stop cleanly. Snapshots complete in seconds because there’s no full VM memory state to checkpoint. Cloning a container to test a configuration change and then rolling back is a two-minute operation, which meaningfully changes how willing you are to experiment with something.
pct migrate. Offline migration works with local storage. Either way, moving a system container between hosts in Proxmox is considerably smoother than migrating equivalent Docker workloads, where service continuity is largely your problem to solve.The Ollama and Open WebUI setup used LXC containers partly for exactly this reason. The services were standard Linux daemons with no kernel-specific requirements, and the iteration cycle in LXC containers was faster than it would have been working through full VM overhead.
The mental model adjustment is simple once you make it: LXC containers in Proxmox are persistent, full-system Linux environments that share the host kernel. Not Docker. Not VMs. Something with its own trade-off profile that fits a specific set of scenarios well and fits others poorly.
What I’m still working through is where LXC starts to show seams as workloads get more complex. At some point in a growing homelab, the pragmatic choice often becomes fewer, larger containers (or VMs) rather than many granular deployments, just from an operational management standpoint. I haven’t found that inflection point for my setup yet, but I’m sure I’ll find it eventually.







