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

VersionEOLRelease
3.0 LTSJune 1st 2023Buster
4.0 LTSJune 1st 2025Bullseye

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

  1. Create lxc-net file if not exists to /etc/default and add the following line:

    USE_LXC_BRIDGE="true"
  2. 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:xx

    And live the rest as is.

  3. 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
Last update: 18/10/2021

Go further

cast_for_education Learn

LXC is lightweight OS-level virtualization. The containers are isolated from the Linux host. LXC easy to install, create, use & manage. Learn how to install, create, use & manage:

mode_comment Discuss

Lxc Manager is an open source project, you can exchange your ideas, or see progress. View all the threads on Lxc Manager

coffee Contribute

LXC Manager is a community driven project and accepts contributions of code and documentation from the community. Why not join us ?