Introduction
Proxmox LXC containers are system containers that share the host kernel but have their own filesystem, network, and processes. They're ideal for running services that don't need full VM isolation — web servers, databases, monitoring agents — with minimal overhead.
LXC vs KVM in Proxmox
| Feature | LXC | KVM |
|---|---|---|
| Overhead | Minimal (< 1%) | Moderate (5-10%) |
| Isolation | Namespace-based | Full hardware |
| Boot time | Seconds | 10-30 seconds |
| Use case | Linux services | Any OS, higher isolation |
| VMs in container | No | Yes |
Downloading Container Templates
BASH
# List available templates
pveam available --section system
# Download Ubuntu template
pveam download local ubuntu-22.04-standard_22.04-1_amd64.tar.zst
# Download Alpine (tiny, 3MB)
pveam download local alpine-3.18-default_20230607_amd64.tar.xz
# List downloaded templates
pveam list localCreating LXC Containers
Via CLI:
BASH
# Create Ubuntu container
pct create 100 local:vztmpl/ubuntu-22.04-standard_22.04-1_amd64.tar.zst --hostname web-server --memory 2048 --swap 512 --cores 2 --net0 name=eth0,bridge=vmbr0,ip=192.168.1.100/24,gw=192.168.1.1 --storage local-zfs --rootfs local-zfs:20 --password SecurePass123 --ssh-public-keys /root/.ssh/id_rsa.pub --unprivileged 1 --features nesting=1
# Start the container
pct start 100
# Enter the container
pct enter 100
# Or SSH directly
ssh root@192.168.1.100Container Configuration
BASH
# View current config
pct config 100
# Change memory
pct set 100 --memory 4096
# Resize disk
pct resize 100 rootfs +10G
# Add additional disk
pct set 100 --mp0 local-zfs:5,mp=/data
# Change network
pct set 100 --net0 name=eth0,bridge=vmbr0,ip=192.168.1.101/24,gw=192.168.1.1Privileged vs Unprivileged Containers
Unprivileged (recommended):- UID/GID mapping: container root (0) maps to host user 100000
- Container can't escape to host even if compromised
- Some limitations: can't mount NFS, some kernel modules unavailable
- Container root = host root
- Required for: Docker-in-LXC, some network functions
- Security risk — use only when necessary
BASH
# Create privileged container
pct create 101 ... --unprivileged 0
# Enable nesting (for Docker inside LXC)
pct set 100 --features nesting=1Docker Inside LXC (Nesting)
BASH
# On privileged container with nesting=1
pct set 100 --features nesting=1,keyctl=1
pct start 100
pct enter 100
# Inside the container
apt update && apt install -y docker.io
systemctl enable docker
docker run -d -p 80:80 nginxSnapshots and Backups
BASH
# Take snapshot
pct snapshot 100 before-update
# List snapshots
pct listsnapshot 100
# Rollback
pct rollback 100 before-update
# Delete snapshot
pct delsnapshot 100 before-update
# Backup container
vzdump 100 --storage backup-storage --mode snapshot
# Restore backup
pct restore 200 /var/lib/vz/dump/vzdump-lxc-100-*.tar.zst --storage local-zfsBind Mounts (Share Host Directories)
BASH
# Share host directory /data/website into container at /var/www
pct set 100 --mp0 /data/website,mp=/var/www
# Shared read-only
pct set 100 --mp0 /data/configs,mp=/etc/myapp,ro=1Networking: Multiple Interfaces and VLANs
BASH
# Add VLAN interface
pct set 100 --net1 name=eth1,bridge=vmbr0,tag=20,ip=10.20.0.100/24
# View all container networks
pct config 100 | grep netMass Deployment Script
BASH
#!/bin/bash
TEMPLATE="local:vztmpl/ubuntu-22.04-standard_22.04-1_amd64.tar.zst"
START_ID=200
COUNT=5
for i in $(seq 1 $COUNT); do
CT_ID=$((START_ID + i))
IP="192.168.1.$((100 + i))/24"
pct create $CT_ID $TEMPLATE --hostname "web-$i" --memory 1024 --cores 1 --net0 name=eth0,bridge=vmbr0,ip=$IP,gw=192.168.1.1 --storage local-zfs --rootfs local-zfs:10 --unprivileged 1 --start 1
echo "Created CT $CT_ID: web-$i ($IP)"
done