LXC Docs
LXC installation documentation
To write this documentation we followed the Debian wiki, and Stéphane GRABER website, you will find the references at the bottom of this document. LXC pronounced leex~cee provide a free software virtualization system for computers running GNU/Linux. For official upstream documentation [please visit lxc]
Supported versions
Version | EOL | Release |
---|---|---|
3.0 LTS | June 1st 2023 | Buster |
4.0 LTS | June 1st 2025 | Bullseye |
LXC Installation
To install lxc on Debian system typically required lxc.
:~# apt install lxc
If you plan to use unprivileged container you need to install required packages.
:~# apt install lxc libvirt0 libpam-cgfs bridge-utils uidmap
Network Installation
To use the container over network, we can virtualize the local network by using bridges. The easiest way install the following packages.
:~# apt install libvirt-clients libvirt-daemon-system iptables ebtables dnsmasq-base libxml2-utils iproute2
:~# virsh net-start default
:~# virsh net-autostart default
Setup Network independent bridge
To set up independent bridge to access from local network, we need to configure different files: /etc/default/lxc-net & /etc/lxc/default.conf
Create lxc-net file if not exists to /etc/default and add the following line:
USE_LXC_BRIDGE="true"
-
Edit default.conf and change the default
lxc.network.type = empty
To this:
lxc.net.0.type = veth
lxc.net.0.link = lxcbr0
lxc.net.0.flags = up
lxc.net.0.hwaddr = 00:16:3e:xx:xx:xxAnd live the rest as is.
Run the command
:~# service lxc-net restart
Enable Network for unprivileged containers
To set up a network for unprivileged containers checks if user namespaces are enabled. Run the following command:
:~# sysctl kernel.unprivileged_userns_clone
kernel.unprivileged_userns_clone = 1
If it reports 0 instead 1, it's disabled.
To enable it, append kernel.unprivileged_userns_clone=1 to /etc/sysctl.conf, or to file such as /etc/sysctl.d/unpriv-usernd.conf, then run sysctl -p
Copy the default file config into your ~/.config/lxc/
cp /etc/lxc/default.conf ~/.config/lxc/default.conf
Configuration
To setup networking and enable it for unprivileged containers, like for containers started by root which by default has a network enabled by default. For non-root containers, we need to allow your non-root user to create a virtual network interface by adding lxc-netuser to /etc/lxc/lxc-usernet with the following line.
:~# echo myusername veth lxcbr0 10 >> /etc/lxc/lxc-usernet
This command creates file lxc-usernet if not exists and append myusername veth lxcbr0 10.
This means "that myusername" is allowed to create up 10 virtual ethernet 'veth' device connected to lxc bridge 'lxcbr0'
Resolve network not starting
Sometimes some containers (unprivileged or not) can not obtaining ip, that can produce if the network has not been started. To resolve the issue, connect to container and restart the network.
:~# lxc-attach xenial
:/# su -
:~# ifconfig eth0 up
:~# ifconfig
eth0 Link encap:Ethernet HWaddr 00:16:3e:ca:11:09
inet addr:10.0.3.68 Bcast:10.0.3.255 Mask:255.255.255.0
inet6 addr: fe80::216:3eff:feca:1109/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:32 errors:0 dropped:0 overruns:0 frame:0
TX packets:17 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:3642 (3.6 KB) TX bytes:1802 (1.8 KB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:324 errors:0 dropped:0 overruns:0 frame:0
TX packets:324 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:25552 (25.5 KB) TX bytes:25552 (25.5 KB)
If you don't still get an ip, check if your resolvconf folder exists:
:~# cd /run/resolvconf/interface
If not exists create the folder, resolve server name & release dhcp:
:~# mkdir /run/resolvconf/interface
:~# resolvconf -u
:~# dhcpclient -r
:~# dhcpclient
:~# ifconfig
If this resolve your issue, but you cannot ping www.debian.org, for example that means you cannot access to internet, in this case resolv.conf file is missing from /run/resolvconf.
:~# echo "nameserver 10.0.3.1" > /run/resolvconf/resolv.conf
:~# echo 'nameserver 127.0.0.53
options edns0' > /run/resolvconf/stub-resolv.conf
:~# /etc/init.d/network restart
After that you should to connect to internet. Thanks to kianmeng
Configure AppArmor
In your ~/.config/lxc/default.conf change lxc.apparmor.profile = generated to one of this option:
- lxc.apparmor.profile = unconfined
- lxc.apparmor.profile = lxc-container-default-cgns
Allow user to create unprivileged containers.
First of all, you need to make sure your user has an uid and gid map defined in /etc/subuid and /etc/subgid, And defined as following.
:~$ more /etc/subuid
myusername:100000:65536
:~$ more /etc/subgid
myusername:100000:65536
The last step is to create an LXC unprivileged you need to add to ~/.config/lxc/default.conf The following lines that represent the preview subuid and subguid:
- lxc.idmap = u 0 100000 65536
- lxc.idmap = g 0 100000 65536
To complete, you need allow lxc to use unprivileged containers, to allow lxc to access to your ~/.local and ~/.local/share, with set acl [acl]:
:~$ setfacl -m u:100000:x /home/myusername/.local
:~$ setfacl -m u:100000:x /home/myusername/.local/share
Privileged Containers (as root)
For all information about all commands for LXC please see: man lxc-'cmd'
To create privileged containers, you need to define the image you want to use. To see all images list, please visit [lxc images list]
An example below:
:~# lxc-create -n mycontainername -t Distribution -- -r Release -a Arch --variant variante
To start a privileged container an example below:
:~# lxc-start mycontainername
To stop a privileged container an example below:
:~# lxc-stop mycontainername
To access to a container you can attach to your terminal, an example below:
:~# lxc-attach mycontainername
To list the containers use the following command `lxc-ls` you can add options. An example below:
~:# lxc-ls -f
NAME
STATE
AUTOSTART
GROUPS
IPV4
IPV6
UNPRIVILEGED
deb11
RUNNING
0
-
10.0.3.22
-
false
ubu18
RUNNING
0
-
10.0.3.27
-
false
alp03
STOPPED
0
-
-
-
false
Debian support IPV6 in stretch, in Debian > 9 IPV6 should be configured manually only enabled by systemd-networkd for more please see [debian IPV6]
Unprivileged Containers (as non-root)
To create unprivileged containers as non-root you must download the image with the command lxc-create an example below:
:~$ lxc-create -n mycontainername -t download -- -d debian -r bullseye -a amd64 --variant default
If the message *ERROR: Unable to fetch GPG key from keyserver* you must append to the command --keyserver with the ubuntu hkp as the url to deliver GPG. An example below :
:~$ lxc-create -n mycontainername -t download -- -d debian -r bullseye -a amd64 --variant default --keyserver hkp://keyserver.ubuntu.com
To start containers you need to use lxc-unprivileged-start, an example bellow:
:~$ lxc-unprivileged-start mycontainername
To list the containers use lxc-ls with options, an example below:
~:$ lxc-ls -f
NAME
STATE
AUTOSTART
GROUPS
IPV4
IPV6
UNPRIVILEGED
deb10
RUNNING
0
-
10.0.3.22
-
true
ubu16
RUNNING
0
-
10.0.3.27
-
true
alp043
STOPPED
0
-
-
-
true
External mounts inside the containers
To mount another filesystem in the container, add to /var/lib/lxc/mycontainer/config:
lxc.mount.entry=/path/in/host/mount_point mount_point_in_container none bind 0 0
Another bind mounts example:
# Exposes /dev/sde in the container
lxc.mount.entry = /dev/sde dev/sde none bind,optional,create=file
Mount FS in a non-privileged container
When a container is unprivileged, the UID or GID of a mounted device has to be root in the container. To make sure we need to map the current user id to lxc.
In ./local/share/lxc/container_name/config
Add Mount file :
lxc.mount.entry = /path/to/host/folder /home/username/.local/share/lxc/foldername/rootfs/path/in/container none bind,rw 0 0
And in .config/lxc/default.conf set mapping
# Container's UID/GID 0-65535 are mapped to host's 100000-165535,
# but UID/GID 1000 on the container is mapped to host's UID/GID 1000.
# replace the previous lxc.idmap set with the following idmap assuming that your uid = 1000 and gid =1000
lxc.idmap = u 0 100000 1000
lxc.idmap = g 0 100000 1000
lxc.idmap = u 1000 1000 1
lxc.idmap = g 1000 1000 1
lxc.idmap = u 1001 101001 64535
lxc.idmap = g 1001 101001 64535
To make sure 1000 correspond to your uid and gid to know your user id
:~$ more /etc/passwd | grep your_user_name
username:x:1000:1000:Username,,,:/home/username:/bin/bash
First 1000 user id, second 1000 group id
Check configuration
Check lxc-configuration to see if everything is enabled. Some time cgroup is not enabled by default it could be simply missing folders /sys/fs/cgroup/systemd & /sys/fs/cgroup/freezer
To enable it
# Create the folders
:~# mkdir /sys/fs/cgroup/systemd
:~# mkdir /sys/fs/cgroup/freezer
:~# mkdir /sys/fs/cgroup/freezer/0
Mount cgroups into them
mount -t cgroup -o name,name=systemd systemd /sys/fs/cgroup/systemd
mount -t cgroup -ofreezer freezer /sys/fs/cgroup/freezer
Check the config again and see if it look like as the following
~:$ lxc-checkconfig
-- Namespaces ---
Namespaces: enabled
Utsname namespace: enabled
Ipc namespace: enabled
Pid namespace: enabled
User namespace: enabled
Network namespace: enabled
--- Control groups ---
Cgroups: enabled
Cgroup v1 mount points:
/sys/fs/cgroup/systemd
/sys/fs/cgroup/freezer
Cgroup v2 mount points:
/sys/fs/cgroup
Cgroup v1 clone_children flag: enabled
Cgroup device: enabled
Cgroup sched: enabled
Cgroup cpu account: enabled
Cgroup memory controller: enabled
Cgroup cpuset: enabled
--- Misc ---
Veth pair device: enabled, loaded
Macvlan: enabled, not loaded
Vlan: enabled, not loaded
Bridges: enabled, loaded
Advanced netfilter: enabled, loaded
CONFIG_NF_NAT_IPV4: missing
CONFIG_NF_NAT_IPV6: missing
CONFIG_IP_NF_TARGET_MASQUERADE: enabled, not loaded
CONFIG_IP6_NF_TARGET_MASQUERADE: enabled, not loaded
CONFIG_NETFILTER_XT_TARGET_CHECKSUM: enabled, loaded
CONFIG_NETFILTER_XT_MATCH_COMMENT: enabled, not loaded
FUSE (for use with lxcfs): enabled, loaded
--- Checkpoint/Restore ---
checkpoint restore: enabled
CONFIG_FHANDLE: enabled
CONFIG_EVENTFD: enabled
CONFIG_EPOLL: enabled
CONFIG_UNIX_DIAG: enabled
CONFIG_INET_DIAG: enabled
CONFIG_PACKET_DIAG: enabled
CONFIG_NETLINK_DIAG: enabled
File capabilities:
Note : Before booting a new kernel, you can check its configuration
usage : CONFIG=/path/to/config /usr/bin/lxc-checkconfig