LXC Containers Installation and Configuration Guide on Ubuntu
P.S. How do I install the latest LTS version of Ubuntu (24.04) on Ubuntu 20.04 and run applications in a container sandboxed environment?
> Tested on: Ubuntu 20.04 / 24.04 (amd64)
> LXC: Classic (not LXD)
Table of Contents
1. Installing LXC
2. Creating a Container
3. Basic Management
4. Network Configuration: Local Network Access
5. SSH Access
6. Btrfs Backend via Loop File
7. Snapshots and Cloning
8. Backup and Restore
9. Useful Commands
10. Troubleshooting
Installing LXC
# Update packages and install LXC
sudo apt update
sudo apt install lxc lxc-templates btrfs-progs
# Check kernel support
lxc-checkconfig
# Check LXC network interfaces
ip ad | grep lxc
> Note: If lxc-checkconfig shows warnings, ensure the kernel has enabled: CONFIG_VETH, CONFIG_MACVLAN, CONFIG_BRIDGE, CONFIG_NET_NS.
Creating a Container
Universal Template
sudo lxc-create -t download -n <NAME> -- \
--dist <distribution> \
--release <version> \
--arch <architecture>
Examples
# Ubuntu 24.04 (Noble)
sudo lxc-create -t download -n bulxc -- \
--dist ubuntu \
--release noble \
--arch amd64
# Ubuntu 22.04 (Jammy)
sudo lxc-create -t download -n mylxc-ubuntu -- \
--dist ubuntu \
--release jammy \
--arch amd64
| Parameter | Description |
|-----------|-------------|
| -t download | Download template for OS images |
| -n <name> | Container name |
| --dist | Distribution (ubuntu, debian, alpine) |
| --release | Release version (noble, jammy, focal) |
| --arch | Architecture (amd64, arm64) |
Basic Management
# List all containers
sudo lxc-ls
# List with details (status, IP, type)
sudo lxc-ls -f
# Start container (in background)
sudo lxc-start -n bulxc -d
# Start in foreground (for debugging)
sudo lxc-start -n bulxc -F
# Attach to container console
sudo lxc-attach -n bulxc
# Exit container
exit
# Stop container
sudo lxc-stop -n bulxc
# Force stop container
sudo lxc-stop -n bulxc --force
# Container information (status, IP, resource usage)
sudo lxc-info -n bulxc
# Delete container (must be stopped first!)
sudo lxc-stop -n bulxc 2>/dev/null
sudo lxc-destroy -n bulxc
Network Configuration: Local Network Access
By default, LXC containers use NAT networking and receive addresses like 10.0.3.x. To make the container visible on your local network (192.168.0.x), configure a bridge.
Step 1: Configure Bridge on Host (Netplan)
1. Find your physical interface name:
ip addr
# Find the interface with your current IP, e.g., eth0 or enp3s0
2. Edit Netplan configuration:
sudo nano /etc/netplan/00-installer-config.yaml
3. Replace configuration (use spaces for indentation, critical!):
network:
version: 2
renderer: networkd
ethernets:
eth0: # Your interface name
dhcp4: no
dhcp6: no
bridges:
br0:
interfaces:
- eth0 # Your interface name
dhcp4: yes # Host gets IP via bridge
dhcp6: no
4. Apply settings:
sudo netplan apply
5. Verify:
ip addr show br0
# br0 should have your local IP (192.168.0.31)
Step 2: Configure Container
1. Stop the container:
sudo lxc-stop -n bulxc
2. Edit container config:
sudo nano /var/lib/lxc/bulxc/config
3. Find the network section and replace with:
lxc.net.0.type = veth
lxc.net.0.link = br0
lxc.net.0.flags = up
lxc.net.0.hwaddr = 00:16:3e:xx:xx:xx
Step 3: Static IP Inside Container
1. Attach to container:
sudo lxc-attach -n bulxc
2. Edit Netplan inside (/etc/netplan/*.yaml):
network:
version: 2
ethernets:
eth0:
dhcp4: no
addresses:
- 192.168.0.32/24 # Desired static IP
routes:
- to: default
via: 192.168.0.1 # Your router/gateway IP
nameservers:
addresses:
- 8.8.8.8
- 1.1.1.1
3. Apply:
netplan apply
4. Verify:
ping -c 3 8.8.8.8
exit
SSH Access
Installing SSH Server Inside Container
# Attach to container
sudo lxc-attach -n bulxc
# Install openssh-server
apt update
apt install openssh-server -y
# Enable auto-start
systemctl enable ssh
systemctl start ssh
Allow Root Login (Optional)
> Warning: Root login via password reduces security. Use SSH keys in production.
# Inside container, edit sshd_config
nano /etc/ssh/sshd_config
Find and modify:
PermitRootLogin yes
PasswordAuthentication yes
Restart SSH:
systemctl restart ssh
exit
Connect from External Device
# From host or another device on the network
ssh root@192.168.0.32
Helpful resources:
- SSH root setup on Ubuntu
Btrfs Backend via Loop File
Enables Btrfs snapshots without a dedicated partition.
Quick Method (Single Command)
sudo lxc-create -t download -n bulxc5 -B loop --fssize 10G --fstype btrfs -- \
--dist ubuntu --release noble --arch amd64
| Parameter | Description |
|-----------|-------------|
| -B loop | Backend: file image as block device |
| --fssize 10G | Size of the image file |
| --fstype btrfs | Filesystem inside the image |
Manual Method (Full Control)
# 1. Create sparse file (10 GB)
sudo fallocate -l 10G /var/lib/lxc/lxc.img
# 2. Attach to loop device
sudo losetup -f --show /var/lib/lxc/lxc.img
# Output: /dev/loop15 remember this device
# 3. Format as Btrfs
sudo mkfs.btrfs -f /dev/loop15
# 4. Mount to separate directory
sudo mkdir -p /var/lib/lxc/btrfs
sudo mount /dev/loop15 /var/lib/lxc/btrfs
# 5. Verify
df -T /var/lib/lxc/btrfs
# Type should be: btrfs
# 6. Create container in this directory
sudo lxc-create -t download -n bulxc-btrfs -B btrfs -- \
--dist ubuntu --release noble --arch amd64
Verify Btrfs
# Check filesystem inside container
sudo lxc-attach -n bulxc5 -- df -T /
# Check subvolumes (on host)
sudo btrfs subvolume list /var/lib/lxc/bulxc5/rootfs
Snapshots and Cloning
> Only works if container was created on Btrfs (backend btrfs or loop + --fstype btrfs)
Create Snapshot
sudo lxc-snapshot -n bulxc5
List Snapshots
sudo lxc-snapshot -n bulxc5 -L
Example output:
snap0 (2024-03-14 10:30:15)
snap1 (2024-03-14 12:45:22)
Restore from Snapshot
# Restore current container to snap0 state
sudo lxc-snapshot -n bulxc5 -r snap0
Clone (New Container from Snapshot)
# Create new container "bulxc5-clone" from snap0
sudo lxc-snapshot -n bulxc5 -r snap0 -N bulxc5-clone
Delete Snapshot
sudo lxc-snapshot -n bulxc5 -d snap0
Helpful resource:
LXC Snapshots and Clones
Backup and Restore
Method 1: Full Archive (tar) Universal
# Stop container for consistency
sudo lxc-stop -n bulxc
# Create backup
sudo tar -czpf /home/ubuntu/lxc/bulxc-$(date +%F).tar.gz \
-C /var/lib/lxc bulxc
# Start container again
sudo lxc-start -n bulxc -d
Restore:
# Extract (container must be stopped and deleted first)
sudo lxc-stop -n bulxc 2>/dev/null
sudo lxc-destroy -n bulxc 2>/dev/null
sudo tar -xzpf /home/ubuntu/lxc/bulxc-2024-03-09.tar.gz \
-C /var/lib/lxc
# Start
sudo lxc-start -n bulxc -d
Method 2: rsync for Incremental Backups
# Stop container
sudo lxc-stop -n bulxc
# Sync with backup directory
sudo rsync -aHAX --delete \
/var/lib/lxc/bulxc/ \
/backup/bulxc-live/
# Start
sudo lxc-start -n bulxc -d
Automation: Backup Script
Create /usr/local/bin/lxc-backup-bulxc.sh:
#!/bin/bash
set -e
CONTAINER="bulxc"
BACKUP_DIR="/home/ubuntu/lxc"
DATE=$(date +%F)
ARCHIVE="$BACKUP_DIR/${CONTAINER}-${DATE}.tar.gz"
# Stop container
lxc-stop -n $CONTAINER 2>/dev/null || true
# Create archive
tar -czpf "$ARCHIVE" -C /var/lib/lxc "$CONTAINER"
# Start container
lxc-start -n $CONTAINER -d
# Clean old backups (keep last 7)
ls -t $BACKUP_DIR/${CONTAINER}-*.tar.gz 2>/dev/null | \
tail -n +8 | xargs -r rm
echo " Backup completed: $ARCHIVE"
Make executable and add to cron:
sudo chmod +x /usr/local/bin/lxc-backup-bulxc.sh
# Edit crontab
sudo crontab -e
# Add line (daily at 03:00):
0 3 * * * /usr/local/bin/lxc-backup-bulxc.sh
Useful Commands
Information and Monitoring
# Container directory size
du -hs /var/lib/lxc/bulxc
# Image file size (for loop backend)
ls -lh /var/lib/lxc/bulxc/rootfs.disk
# Resize image (loop backend)
sudo lxc-storage-disk-resize bulxc 20G
# Active loop devices
losetup -a
# Container network interfaces
sudo lxc-attach -n bulxc -- ip addr
Resource Management
# Limit CPU (in container config)
# /var/lib/lxc/bulxc/config
lxc.cpu.cfs_quota_us = 50000
lxc.cpu.cfs_period_us = 100000
# Limit memory
lxc.memory.limit = 1GB
Network
# Check container IP
sudo lxc-attach -n bulxc -- hostname -I
# Port forwarding (in container config)
# Access container port 80 from host port 8080
lxc.net.0.ipv4.address = 192.168.0.32/24
Troubleshooting
systemd fails to start: Failed to fork off sandboxing environment
Cause: cgroups v1 (host) vs v2 (Ubuntu 24.04 container) conflict.
Solution: Enable cgroups v2 on host:
# 1. Edit GRUB
sudo nano /etc/default/grub
# Add to line:
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash systemd.unified_cgroup_hierarchy=1"
# 2. Update and reboot
sudo update-grub
sudo reboot
# 3. Verify
mount | grep cgroup
# Should show: cgroup2 on /sys/fs/cgroup type cgroup2
Alternative: Use Ubuntu 22.04 in container it's more compatible with cgroups v1.
Container Has No Network Access
# Check network config
sudo nano /var/lib/lxc/bulxc/config
# Ensure: lxc.net.0.link = br0
# Check bridge on host
ip addr show br0
brctl show br0 # if bridge-utils installed
# Check AppArmor
sudo dmesg | grep -i apparmor
# If needed, temporarily:
# lxc.apparmor.profile = unconfined
Btrfs: is not a valid backing storage type
Cause: btrfs backend requires /var/lib/lxc to be on a Btrfs partition.
Solution: Use loop backend with --fstype btrfs:
sudo lxc-create -t download -n bulxc -B loop --fstype btrfs -- \
--dist ubuntu --release noble --arch amd64
No SSH Access
# Inside container, check:
systemctl status ssh
ss -tlnp | grep :22
ufw status # if firewall enabled
# Allow port (if needed)
ufw allow 22/tcp
Helpful Links
LXC File Structure
/var/lib/lxc/
<container-name>/
config # Container configuration
rootfs/ # Root filesystem (or link to loop file)
rootfs.disk # Image file (for loop backend)
snaps/ # Snapshots (for Btrfs)
snap0/
snap1/
lxc.conf # Global config (rarely used)
/etc/lxc/
default.conf # Template for new containers
lxc-net.conf # Network service settings
> Tip: Always test restore from backup on a test container before deleting the original. A backup without restore verification is not a backup.