Skip to content
Go back

LXC vs Docker: Lightweight Containers

By SumGuy 9 min read
LXC vs Docker: Lightweight Containers

The Container That Forgot It Was a VM

You’ve got Proxmox running at home. You want to spin up a dev environment. Your buddy says “just Docker it.” You say “I’m pretty sure I need systemd running in here.” They look confused. You look confused. Welcome to the gap between LXC and Docker — two things called “containers” that are solving entirely different problems.

Here’s the thing: Docker and LXC are cousins, not twins. They both use Linux namespaces and cgroups under the hood, but they’re pointing in opposite directions. Docker is all about packaging a single application into an immutable artifact that runs the same way everywhere. LXC is about running a lightweight, persistent operating system that just happens to share a kernel with your host.

One is a shipping container full of identical cardboard boxes. The other is a studio apartment with running water and electricity. Both are “containers.” Only one makes sense when you need a full OS.

What’s Actually Different? (Beyond the Marketing)

Let’s demystify the machinery. Both technologies share the same Linux kernel isolation tools — namespaces and cgroups. The difference is how they’re stacked.

Docker: The Application Container

Docker wraps a single application (Nginx, Redis, your Python service) inside a layered filesystem with its own minimal OS (Alpine, Debian slim, or busybox). When you run a Docker container, you get:

Docker’s philosophy: immutability. Rebuild and redeploy instead of patching. Perfect for stateless microservices and CI/CD pipelines.

LXC: The System Container

LXC runs a full Linux distribution inside the container. You get:

LXC’s philosophy: lightweight virtualization. It’s a VM that doesn’t need its own kernel.

The mental model: Docker is “package my app”, LXC is “give me a minimal OS to run stuff on.”

Kernel Sharing: The Secret Sauce

Both use the same kernel. Your host Linux kernel runs all containers. This is why Docker on a Mac or Windows feels janky — they’re running a hidden Linux VM, and the Docker containers run inside that VM.

LXD (the modern “Linux Container Daemon” — LXC’s successor/management layer) and Incus (the Canonical-backed fork) make LXC containers easier to manage. They abstract away the config complexity. When you say “run an LXC container,” you’re usually invoking LXD or Incus, not raw LXC.

The shared kernel means:

On a modern system, a running LXC container might use 30-100 MB of RAM just sitting there. A VM starts at 512 MB–2 GB, plus whatever the bootloader and OS demand. That’s the gap.

When LXC Wins (And It’s Your Homelab)

You’re running Proxmox. You want to spin up a Postgres database, an Nginx reverse proxy, and a background job queue. You could:

Option A (Docker): Three separate containers, a bridge network, volumes for persistence, maybe Docker Compose orchestration. Very clean, very modern, very “one process per container.”

Option B (LXC): One container with a full Ubuntu install, systemd managing all three services, a single bind mount to your host data directory, and you just lxc exec container -- apt install postgresql nginx or configure it with Ansible. The whole thing boots in 2 seconds.

LXC wins here because:

  1. Multi-process workloads feel natural. You’re not fighting the “one process per container” constraint.
  2. Bind mounts are simpler. Instead of Docker volumes with permission headaches, you just mount /mnt/data directly to the host. No copy-on-write overhead.
  3. Init system integration. systemd is running. Cron jobs work. Service restarts are handled by systemd, not orchestration tooling.
  4. Persistent root filesystem. Your container survives reboots. You can SSH into it, debug, tweak configs, and not worry about drifting from your Compose file.
  5. Legacy software. Got a hairy old application that needs running as a proper service with environment variables, signal handling, and a process group? LXC runs it. Docker makes you fight the “run as PID 1” weirdness.

Concrete LXC Example

Here’s a Proxmox LXC container running Postgres + a simple Nginx proxy:

Terminal window
# Create container (via Proxmox UI or CLI)
lxc launch ubuntu:22.04 myapp
# Enter it
lxc shell myapp
# Inside the container:
apt update && apt install -y postgresql postgresql-contrib nginx
# Start services (systemd runs them automatically on reboot)
systemctl restart postgresql
systemctl restart nginx
# Bind mount your data directory from the host
# (done at container creation or via `lxc config device add`)
# And you're done. SSH in whenever you want.
ssh root@<container-ip>

That’s it. No Compose file. No volume mounts. No networking plumbing. You’ve got a lightweight OS.

When Docker Wins (Most Deployments)

Docker dominates because:

  1. Immutable deploys. Rebuild the image, push it, deploy it. No drift. Every environment is identical.
  2. Image registry ecosystem. Docker Hub, GitHub Container Registry, private registries. Sharing is baked in.
  3. Stateless by design. Forces you to externalize state (databases, caches, object storage). Better architecture.
  4. Orchestration maturity. Docker Swarm, Kubernetes, Nomad. Tons of tooling to manage many containers.
  5. Single responsibility. One process per container. Easy to reason about, easy to scale horizontally.

Concrete Docker Example

Same workload, Docker style:

version: '3.8'
services:
postgres:
image: postgres:15-alpine
environment:
POSTGRES_PASSWORD: insecure123
volumes:
- pgdata:/var/lib/postgresql/data
ports:
- "5432:5432"
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- postgres
volumes:
pgdata:

Then:

Terminal window
docker compose up -d

You’ve got the same services, isolated, version-controlled in a single file, deployable anywhere Docker runs. Trade-off: each service is a separate container, networking is explicit, volumes require thinking about lifecycle.

The LXD / Incus Situation

LXD (made by Canonical) was the modern way to manage LXC containers — better CLI, snapshots, proper networking, profiles. Then Canonical moved LXD to a proprietary model, and the community forked it as Incus. Most people building new stuff use Incus now.

Both work the same way for your purposes. On Proxmox, you’re using LXC directly (Proxmox has native LXC support), so this is mostly academic unless you’re on Ubuntu or using standalone LXD/Incus.

Security: The Asterisk

Docker containers are application sandboxes. Each container runs one app with minimal OS.

LXC containers are lightweight VMs. They run a full OS with root and everything. That’s powerful but also means:

For a home lab, this is fine. For production or multi-tenant, you’d want proper user namespace remapping and security profiles.

Docker pushes security as a feature: “you can run untrusted code safely.” LXC is more: “it’s a lightweight VM, secure it like you’d secure a VM.” Different threat models.

Resource Reality Check

Here’s the math. On a 16 GB system:

The difference between Docker and LXC containers at scale is small. The difference between containers and VMs is massive.

For a single persistent workload (Postgres, a background queue, your media server), LXC’s slightly smaller overhead doesn’t matter. The convenience of a single init-managed system matters more.

When to Pick What

Here’s your decision tree:

Use Docker if:

Use LXC if:

Use both if:

The Honest Take

Docker is the industry standard because it solved a real problem: immutable deployments and dev/prod parity. It’s excellent at what it does.

LXC is ignored in most DevOps conversations because it doesn’t fit the “stateless microservice” model. But for a home lab, a single server, or a workload that needs persistent state and systemd? LXC is simpler and more natural.

The mistake is thinking you have to pick one. Docker and VMs both exist. LXC is the bridge — lightweight virtualization when containers feel too minimal and VMs feel too heavy.

Your Proxmox box can run both LXC containers (for long-lived stuff) and Docker (if you spin up an Ubuntu container and install Docker in it, though that’s a bit meta). Different tools, different contexts, different problems.

That’s the real distinction. Docker and LXC aren’t fighting for the same job. Docker is asking “how do I package and deploy applications?” LXC is asking “how do I run a bunch of stuff on minimal hardware without booting full VMs?”

Both valid questions. Now you know which one to ask first.


Share this post on:

Send a Webmention

Written about this post on your own site? Send a webmention and it'll show up above once verified.


Next Post
Argo Workflows vs Tekton

Discussion

Powered by Garrul . Sign in with GitHub or Google, or post anonymously.

Related Posts