LXC and Docker both use Linux kernel features — namespaces, cgroups, and layered filesystems — to create isolated environments, but they serve fundamentally different purposes. LXC creates system containers: lightweight alternatives to virtual machines that run a full init system, multiple processes, and behave like a complete Linux installation. Docker creates application containers: single-process environments designed to package and run one application.

Understanding this distinction is critical for choosing the right tool. Running a full LAMP stack in a single Docker container is fighting the tool. Running a microservice in LXC is using a sledgehammer to hang a picture.

Architecture Comparison

Aspect LXC / LXD Docker
Container type System container (full OS) Application container (single process)
Init system systemd, OpenRC, etc. No init (PID 1 is the app)
Multiple processes Yes (like a VM) Discouraged (one process per container)
Image format Filesystem image or directory Layered OCI images
Image distribution LXD image server Docker Hub, OCI registries
Lifecycle management LXD (or raw LXC tools) Docker daemon + CLI
Networking Bridge, macvlan, SR-IOV Bridge, overlay, macvlan
Storage ZFS, Btrfs, LVM, dir overlay2, btrfs, devicemapper
Typical use case Lightweight VM replacement Microservices, CI/CD

Kernel Namespaces: Same Foundation, Different Usage

Both LXC and Docker use the same kernel namespace primitives, but they configure them differently:

# LXC container namespaces - similar to a full OS
# The container runs systemd as PID 1 and manages its own services
lxc-info -n my-container -p
# PID: 12345 (this is systemd inside the container)

# Docker container namespaces - minimal
# PID 1 is the application itself
docker inspect --format '{{.State.Pid}}' my-app
# 67890 (this is the application process)

LXC containers typically use user namespaces by default (via LXD), mapping container root to an unprivileged host UID. Docker does not enable user namespaces by default, though it can be configured. This gives LXC an out-of-the-box security advantage for system container workloads.

LXD: The Modern LXC Management Layer

LXD (now maintained by Canonical as Incus in the community fork) provides a user-friendly management layer on top of LXC:

# Initialize LXD
sudo lxd init

# Launch an Ubuntu system container
lxc launch ubuntu:24.04 my-server

# The container is now running a full Ubuntu system with systemd
lxc exec my-server -- systemctl status
# Shows systemd services running inside the container

# Install and run multiple services
lxc exec my-server -- apt install nginx postgresql
lxc exec my-server -- systemctl enable --now nginx postgresql

# Manage like a real server
lxc exec my-server -- bash

# Create a snapshot
lxc snapshot my-server pre-upgrade

# Restore from snapshot
lxc restore my-server pre-upgrade

LXD Profiles

# Create a profile for web servers
lxc profile create web-server
lxc profile edit web-server

# web-server profile
config:
  limits.cpu: "2"
  limits.memory: 2GB
  security.nesting: "false"
  security.privileged: "false"
description: Web server profile
devices:
  eth0:
    name: eth0
    network: lxdbr0
    type: nic
  root:
    path: /
    pool: default
    size: 20GB
    type: disk

# Launch with profile
lxc launch ubuntu:24.04 web1 --profile web-server

Performance Comparison

Both LXC and Docker containers have near-native performance since they share the host kernel. The differences are in startup time, resource overhead, and I/O patterns:

Metric LXC/LXD Docker VM (KVM)
Startup time 1-3 seconds Under 1 second 10-30 seconds
Memory overhead ~30-50 MB (full OS) ~5-10 MB (app only) ~200+ MB
CPU overhead ~0% (shared kernel) ~0% (shared kernel) ~2-5% (hypervisor)
Disk I/O Near-native Near-native (overlay2) Near-native (virtio)
Network I/O Near-native Near-native (bridge) 95-98% native (virtio-net)
Density (per host) Dozens to hundreds Hundreds to thousands Tens

Networking

LXC/LXD Networking

# LXD creates a managed bridge by default
lxc network list
# +--------+----------+---------+
# |  NAME  |   TYPE   | MANAGED |
# +--------+----------+---------+
# | lxdbr0 | bridge   | YES     |
# +--------+----------+---------+

# Create a macvlan network (container gets its own IP on the LAN)
lxc network create macvlan0 \
  type=macvlan \
  parent=eth0

# Attach container to macvlan
lxc network attach macvlan0 my-server eth0

# LXD supports network ACLs
lxc network acl create web-acl
lxc network acl rule add web-acl ingress action=allow \
  protocol=tcp destination=0.0.0.0/0 destination_port=80,443
lxc network acl rule add web-acl ingress action=deny

Docker Networking

# Docker uses user-defined bridge networks
docker network create --driver bridge my-app-network

# Docker overlay networks for multi-host
docker network create --driver overlay --attachable my-overlay

# Docker also supports macvlan
docker network create -d macvlan \
  --subnet=192.168.1.0/24 \
  --gateway=192.168.1.1 \
  -o parent=eth0 \
  my-macvlan

LXD networking feels more like managing VMs: each container can get its own IP on the physical network. Docker networking is designed for service-to-service communication with port mapping to the host. Choose based on whether your workload needs to be a "citizen on the network" (LXC) or a "service behind a proxy" (Docker).

Storage

# LXD storage pools
lxc storage list
lxc storage create my-pool zfs source=/dev/sdb

# ZFS features: snapshots, clones, compression, send/receive
lxc storage volume create my-pool data size=50GB
lxc storage volume attach my-pool data my-server /data

# Docker storage
# Primarily overlay2 for image layers
# Named volumes for persistent data
docker volume create --driver local my-data

LXD's ZFS integration is significantly more mature than Docker's storage options. ZFS snapshots, replication, and compression work seamlessly with LXD containers, making it an excellent choice for environments where data management is a priority.

Security Comparison

Security Feature LXC/LXD Docker
User namespaces Enabled by default Disabled by default
AppArmor Per-container profiles docker-default profile
Seccomp Default seccomp profile Default seccomp profile
Privileged mode Discouraged, rarely needed Common (--privileged flag)
Root daemon LXD daemon (root) Docker daemon (root)
Rootless mode Supported via user namespaces Supported (rootless Docker)

Proxmox LXC

Proxmox VE integrates LXC containers alongside KVM virtual machines, providing a web-based management interface:

# Create an LXC container in Proxmox
pct create 100 local:vztmpl/ubuntu-24.04-standard_24.04-1_amd64.tar.zst \
  --hostname web-server \
  --memory 2048 \
  --cores 2 \
  --net0 name=eth0,bridge=vmbr0,ip=dhcp \
  --storage local-zfs \
  --rootfs local-zfs:20

# Start the container
pct start 100

# Enter the container
pct enter 100

# Proxmox-specific features:
# - Live migration between nodes
# - Backup/restore with vzdump
# - Firewall per container
# - Resource pools and permissions

Proxmox LXC is an excellent choice for homelab and small business environments where you want VM-like management of lightweight containers without the overhead of full virtualization.

When to Use Each

Choose LXC/LXD When:

  • You need a lightweight VM replacement (full OS environment)
  • Your application requires multiple services (web server + database + cron)
  • You want to manage the container like a traditional server (SSH in, install packages)
  • You are migrating from VMs and want to reduce overhead
  • You need persistent, long-lived environments for development
  • You use Proxmox and want containers alongside VMs

Choose Docker When:

  • You are building microservices (one process per container)
  • You need a reproducible build system (Dockerfiles)
  • You want a vast ecosystem of pre-built images (Docker Hub)
  • Your workflow involves CI/CD pipelines
  • You need container orchestration (Kubernetes, Docker Swarm)
  • You value immutable infrastructure and declarative configuration

Running Docker Inside LXC

A common pattern is running Docker inside an LXC container, getting the benefits of both:

# Enable nesting for the LXC container (LXD)
lxc config set my-docker-host security.nesting true

# For Proxmox LXC, enable features in the container config
# /etc/pve/lxc/100.conf
features: nesting=1,keyctl=1

# Inside the LXC container, install Docker normally
apt install docker.io docker-compose-v2

# Docker runs inside the LXC container with its own isolation
# The LXC container provides an additional security boundary
Tip: Running Docker inside LXC is a popular pattern in Proxmox homelab setups. It gives you the management benefits of Proxmox (snapshots, backups, live migration) while still using Docker for application deployment. The LXC container acts as a lightweight VM that hosts your Docker environment.

Migration Between LXC and Docker

Migration between the two is not straightforward because they represent different paradigms. However, there are practical approaches:

LXC to Docker

# Export the LXC filesystem
lxc export my-server my-server-backup.tar.gz

# This is NOT directly importable as a Docker image
# Instead, identify the services running in LXC and create
# separate Dockerfiles for each:

# 1. Export application data
lxc file pull my-server/var/www/html/ ./app-data/ -r
lxc exec my-server -- pg_dump mydb > database.sql

# 2. Create Docker images for each service
# 3. Create a docker-compose.yml
# 4. Import the data into Docker volumes

Docker to LXC

# Create an LXC container and install services
lxc launch ubuntu:24.04 my-new-server

# Import Docker container data
docker cp my-app:/var/www/html ./app-data/
lxc file push ./app-data/ my-new-server/var/www/html/ -r

# Install and configure services inside LXC
lxc exec my-new-server -- apt install nginx postgresql
lxc exec my-new-server -- systemctl enable --now nginx

The fundamental difference between LXC and Docker is philosophical: LXC treats containers as machines, Docker treats them as processes. Neither is objectively better. The right choice depends on whether you are managing infrastructure (LXC) or deploying applications (Docker). Many sophisticated environments use both, with LXC providing the hosting layer and Docker providing the application deployment layer.