← Back

LXC Container Deployment on Debian — Full Guide

📅 2026-06-15

1. Debian Host Setup

Install LXC

apt update && apt install -y lxc debootstrap bridge-utils iptables-persistent

This pulls in: - lxc — the container runtime - debootstrap — builds base system from apt repositories - bridge-utils — for brctl - iptables-persistent — makes iptables rules survive reboots

Enable IP forwarding

echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.d/99-lxc.conf
sysctl -p /etc/sysctl.d/99-lxc.conf

Check cgroup version

Debian 12 (Bookworm) uses cgroup2 by default. Verify:

cat /sys/fs/cgroup/cpu.max
# Expected: "100000 100000" or similar (quota 100ms per 100ms period = 1 CPU)

If this returns content, cgroup2 cpu controller is active — the lxc.cgroup2.cpu.max setting will work.

Create bridge (br0 = LAN)

Edit /etc/network/interfaces:

# /etc/network/interfaces — eth0 is the host's physical WAN/NIC
auto lo
iface lo inet loopback

auto eth0
iface eth0 inet manual

auto br0
iface br0 inet static
    address 192.168.2.1/24
    gateway 192.168.2.254
    bridge-ports eth0
    bridge-stp off
    bridge-fd 0

Warning: If you're SSH'd into this machine and change the interface that carries your SSH session, you may lose connectivity. Do this from console or have fallback access.

Restart networking:

systemctl restart networking

Verify:

ip addr show br0

Set FORWARD policy to ACCEPT

iptables -P FORWARD ACCEPT
# This survives reboots because of iptables-persistent installed above

2. Create Container

Option A — download template (recommended)

apt install -y lxc-templates
lxc-create -n debian-ct -t download -- -d debian -r bookworm -a amd64

This downloads a pre-built Debian rootfs. After creation, configure the network (section 3) and start.

Option B — debootstrap (manual rootfs)

apt install -y debootstrap
mkdir -p /var/lib/lxc/debian-ct/rootfs
debootstrap bookworm /var/lib/lxc/debian-ct/rootfs http://deb.debian.org/debian

Then configure the LXC config manually (section 3).


3. Configure Networking Inside Container

With lxc-create -t download, the rootfs is at /var/lib/lxc/debian-ct/rootfs. Edit the network config:

nano /var/lib/lxc/debian-ct/rootfs/etc/network/interfaces
auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
    address 192.168.2.10/24
    gateway 192.168.2.254

Or DHCP:

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet dhcp

Set hostname:

echo 'debian-ct' > /var/lib/lxc/debian-ct/rootfs/etc/hostname

Add hosts entry:

cat > /var/lib/lxc/debian-ct/rootfs/etc/hosts << 'EOF'
127.0.0.1 localhost
127.0.1.1 debian-ct
EOF

4. LXC Config

nano /var/lib/lxc/debian-ct/config
# ── UPDATE THESE 3 LINES before starting ──
lxc.uts.name = debian-ct           # ← container name (change this)
lxc.rootfs.path = dir:/var/lib/lxc/debian-ct/rootfs   # ← must match
lxc.net.0.hwaddr = 00:11:22:33:44:55  # ← generate: openssl rand -hex 6 | sed 's/\(..\)/\1:/g'

lxc.include = /usr/share/lxc/config/debian.conf
lxc.arch = linux64

# Memory cap
lxc.cgroup2.memory.max = 512M
lxc.cgroup2.memory.high = 384M

# CPU & process limits
lxc.cgroup2.cpu.weight = 102
lxc.cgroup2.cpu.max = "1 4"
lxc.cgroup2.memory.swap.max = 256M
lxc.cgroup2.pids.max = 1024

# Autostart on boot
lxc.start.auto = 1
lxc.start.delay = 0

# Network: veth → br0
lxc.net.0.type = veth
lxc.net.0.link = br0
lxc.net.0.flags = up

# Mount auto — let lxcfs handle cgroup/proc/sys automatically
lxc.mount.auto = proc:mixed sys:mixed cgroup:rw:force

Generate a unique MAC address: bash openssl rand -hex 6 | sed 's/\(..\)/\1:/g'


5. Start / Stop the Container

# Start (daemonized — runs in background)
lxc-start -n debian-ct -d

# Check status
lxc-info -n debian-ct

# Stop (10s timeout before SIGKILL)
lxc-stop -n debian-ct -t 10

# Start in foreground (see all logs live — useful for debugging)
lxc-start -n debian-ct -F

# Enter the container (run commands inside)
lxc-attach -n debian-ct

-d = daemonize (background). -F = foreground (debugging). -t N = timeout seconds on stop.


6. Known Issues & Fixes

Issue: "Failed to set cpu.max"

On some Debian setups the cpu controller is in cgroup1 (no cpu.max file). Comment out the line:

# In /var/lib/lxc/debian-ct/config, comment out:
# lxc.cgroup2.cpu.max = "1 4"

Verify on your host:

cat /sys/fs/cgroup/cpu.max
# If empty or "max", cgroup2 cpu controller is not active

Issue: "Address not available" on MAC assignment

Remove the lxc.net.0.hwaddr line or use a different MAC. Let LXC auto-generate one.

Issue: Container gets no IP from DHCP

Make sure isc-dhcp-client is installed inside the container:

lxc-attach -n debian-ct -- apt install -y isc-dhcp-client

Issue: SSH keys conflict on rebuild

When rebuilding a container, SSH host keys are regenerated on first boot. Remove old keys inside the container:

rm -f /var/lib/lxc/debian-ct/rootfs/etc/ssh/ssh_host_*

7. Alpine vs Debian Differences

Aspect Alpine Debian
Package manager apk apt
Init system OpenRC systemd
Cgroup setup May need manual cgroup2 mount cgroup2 by default (Bookworm+)
CPU cgroup cpu.max may not exist Usually works out of box
Network config /etc/network/interfaces /etc/network/interfaces
LXC templates lxc-create -t download lxc-create -t download
Firewall iptables / nftables iptables / nftables

Quick Reference — Full Config

Host /etc/network/interfaces:

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet manual

auto br0
iface br0 inet static
    address 192.168.2.1/24
    gateway 192.168.2.254
    bridge-ports eth0
    bridge-stp off
    bridge-fd 0

LXC /var/lib/lxc/debian-ct/config:

# ── UPDATE THESE 3 LINES before starting ──
lxc.uts.name = debian-ct           # ← container name (change this)
lxc.rootfs.path = dir:/var/lib/lxc/debian-ct/rootfs   # ← must match
lxc.net.0.hwaddr = 00:11:22:33:44:55  # ← generate: openssl rand -hex 6 | sed 's/\(..\)/\1:/g'

lxc.include = /usr/share/lxc/config/debian.conf
lxc.arch = linux64

# Memory cap
lxc.cgroup2.memory.max = 512M
lxc.cgroup2.memory.high = 384M

# CPU & process limits
lxc.cgroup2.cpu.weight = 102
lxc.cgroup2.cpu.max = "1 4"
lxc.cgroup2.memory.swap.max = 256M
lxc.cgroup2.pids.max = 1024

# Autostart on boot
lxc.start.auto = 1
lxc.start.delay = 0

# Network: veth → br0
lxc.net.0.type = veth
lxc.net.0.link = br0
lxc.net.0.flags = up

# Mount auto — let lxcfs handle cgroup/proc/sys automatically
lxc.mount.auto = proc:mixed sys:mixed cgroup:rw:force

Container /etc/network/interfaces:

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
    address 192.168.2.10/24
    gateway 192.168.2.254