What is LXC?
LXC (Linux Containers) is an OS-level virtualization method that runs multiple isolated Linux systems on a single host using a shared kernel. Unlike full virtual machines, LXC containers share the host OS kernel while maintaining their own filesystem, processes, and network stack. This design makes them extremely lightweight and fast to start.
LXC vs Virtual Machines
The choice between LXC containers and VMs depends on your isolation and performance requirements:
| Feature | LXC Container | VM (KVM/QEMU) |
|---|---|---|
| Startup time | Milliseconds to seconds | Seconds to minutes |
| Memory overhead | Minimal (only app memory) | Full OS memory per guest |
| Disk space | 100 MB–1 GB | 2–10+ GB |
| Kernel | Shares host kernel | Independent kernel |
| Isolation | Process-level | Hardware-level |
| Best for | Web servers, microservices, dev environments | Multi-tenant, different OS kernels, full isolation |
Downloading Templates
Proxmox provides pre-built container templates via pveam. To list available templates from TurnKey Linux and others:
pveam update
pveam available --section turnkeylinux
Download a template to your local storage:
pveam download local ubuntu-22.04-standard_22.04-1_amd64.tar.zst
Creating a Container
Create a container from the CLI or web UI. The essential parameters include hostname, password, storage volume, and network configuration:
pct create 100 local:vztmpl/ubuntu-22.04-standard_22.04-1_amd64.tar.zst \
--hostname web01 \
--password securePass123 \
--storage local-lvm \
--net0 name=eth0,bridge=vmbr0,ip=dhcp \
--unprivileged 1
pct start 100
Key flags control root password, SSH keys, DNS servers, and CPU/memory allocation.
Unprivileged vs Privileged Containers
Unprivileged containers run with UID/GID mapping via subuid and subgid ranges, mapping root (UID 0) inside the container to a high-numbered unprivileged UID on the host. This prevents container root from having host root access:
# Default mapping: container UID 0 maps to host UID 100000
# /etc/subuid contains: root:100000:65536
Privileged containers run as real root on the host. They offer better filesystem compatibility but lower security.
Key trade-off: Unprivileged containers cannot mount most filesystems (NFS, fuse, bind mounts of host directories) because the kernel blocks unprivileged mounts. If you need NFS mounts or FUSE inside a container, use a privileged container and restrict access with AppArmor.
Resource Limits
Proxmox uses cgroups to enforce resource limits on containers:
| Resource | Parameter | Example |
|---|---|---|
| CPU quota | cpulimit | 50 (50% of one core) |
| CPU cores | cores | 4 |
| Memory | memory | 2048 (MB) |
| Swap | swap | 512 (MB) |
| Disk IOPS | bwlimit | 100 (MB/s) |
Set limits at creation or via pct set:
pct set 100 --memory 2048 --swap 512 --cpulimit 50 --cores 2
Bind Mounts
Bind mounts share host directories with a container. For unprivileged containers, you must map the UID/GID correctly using the map option:
pct set 100 --mp0 /mnt/storage/data,mp=/srv/data,acl=1
Add the mount point entry in /etc/pve/lxc/100.conf if you need root squash mapping:
mp0: /mnt/storage/data,mp=/srv/data,rootuid=1000,rootgid=1000
For privileged containers, bind mounts work without UID remapping, making them simpler for shared storage.
Snapshots and Cloning
Snapshots capture the container state at a point in time with minimal space overhead (COW):
pct snapshot 100 pre-upgrade --description "Before PHP 8.3 upgrade"
List and rollback snapshots:
pct listsnapshot 100
pct rollback 100 pre-upgrade
Clone a container from a template or snapshot for testing:
pct clone 100 101 --hostname staging-web
Networking Modes
Containers support three network models:
- Bridged (vmbr) — Container appears as a device on the physical network, gets its own MAC and IP via DHCP. Default and most common.
- Routed — Container uses a virtual network behind the host, with
iptablesforwarding. Useful when you control the upstream routing. - NAT — Container gets a private IP behind the host, masqueraded to the physical network. Simple but no inbound access without port forwarding.
Backup and Restore
Use vzdump for consistent container backups with quiescing:
vzdump 100 --mode suspend --compress zstd --storage backup-store
To restore a container from backup:
pct restore 200 /var/lib/vz/dump/vzdump-lxc-100-2024_05_22-00_00_00.tar.zst \
--storage local-lvm
Practical Use Cases
- Web server — Lightweight Nginx/Apache containers, each isolated per site.
- Database — MySQL/PostgreSQL in containers with bind-mount to ZFS datasets for snapshots.
- Docker-in-LXC — Works in privileged containers with
nesting=1. Not recommended for production due to Docker’s own isolation model conflicting with LXC cgroups.
