Posts and how to...

Many useful articles and instructions!

    How to install and configure an LXC container with the latest LTS 24.04 version on Ubuntu 20.04 and 24.04, create backups, and configure it so that the data is stored in a single .img file

    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:


    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.