systemd-nspawn
is a lightweight container tool that comes with systemd, designed to run a command or OS environment in a tightly isolated environment. Often described as "chroot on steroids," it provides a convenient way to test or run entire Linux distributions or minimal environments in a secure and controlled manner.
Unlike full virtualization solutions like QEMU or container platforms like Docker, systemd-nspawn
uses Linux namespaces and cgroups to create containers with very little overhead.
Containers using nspawn can be run from any location on your filesystem, but the recommended folder is /var/lib/machines
. Inside this folder, we create a subfolder that holds our Linux/GNU rootfs. To simplify the process, this article guides you through creating a container template. The contents of that template folder can then be copied to a new location and used as a new container environment.
sudo su
/var/lib/machines
:cd /var/lib/machines
mkdir template
As a container can hold any distribution's rootfs, you are relatively free in your choice. We provide a list of minimal distribution tarballs, such as Debian, Ubuntu, and BredOS; however, please be aware that this article is specifically for a BredOS container.
Any commands that need to be run inside your container must be adjusted according to your distribution's variant if you are not using BredOS.
.tar.gz
for your CPU architecture..tar.gz
for your CPU architecture.Container Base
or Container Minimal Base
..tar.zst
file.latest
and aarch64
or armv7
tag.A BredOS rootfs will be available soon!
After downloading your chosen rootfs tarball, it needs to be extracted. In this example, we downloaded the Arch Linux ARM tarball and converted it to BredOS.
/var/lib/machines/template
:tar -xzf <your distro's tarball of choice> -C /var/lib/machines/template
template
should look like this:ls template/
bin boot dev etc home lib mnt opt proc root run sbin srv sys tmp usr var
systemd-nspawn --machine="Template" --directory=/var/lib/machines/template
The parameter --machine
defines the name of the container, while --directory
points to the location of the container. To exit the container, use either Ctrl + D or type Ctrl + ] three times within one second.
The first thing we want to do inside the container is initialize our package manager and update the system.
pacman-key --init
pacman-key --populate
pacman -Syu
If you encounter problems resolving hostnames, remove the file
/var/lib/machines/template/etc/resolv.conf
from the host system.
pacman -R linux-aarch64 linux-firmware
pacman-key --recv-keys 77193F152BDBE6A6 BF0740F967BA439D DAEAD1E6D799C638 1BEF1BCEBA58EA33
pacman-key --lsign-key 77193F152BDBE6A6 BF0740F967BA439D DAEAD1E6D799C638 1BEF1BCEBA58EA33
echo -e '# --> BredOS Mirrorlist <-- #\n\n# BredOS Main mirror\nServer = https://repo.bredos.org/repo/$repo/$arch\n' | tee /etc/pacman.d/bredos-mirrorlist
nano /etc/pacman.conf
[BredOS-any]
Include = /etc/pacman.d/bredos-mirrorlist
[BredOS]
Include = /etc/pacman.d/bredos-mirrorlist
Save and close the file with Ctrl + X and Y
pacman -Syu bred-os-release BredOS-any/lsb-release bredos-logo
pacman -Sy bredos-config bredos-news
The container we created in section 2. Create container template used the network of your hostsystem. If you prefer a virtual network device on your container, for example if you want to use Open vSwitch, do the following.
mkdir /var/lib/machines/template-veth
rsync -avP /var/lib/machines/template/* /var/lib/machines/template-veth/
To simplify this guide we will continue working with our template created in 2. Create container template.
systemd-nspawn --machine="Template" --directory=/var/lib/machines/template
To keep the systemd theme, we use systemd-networkd
to configure our virtual network device.
touch /etc/systemd/network/80-container-host0.network
nano /etc/systemd/network/99-wolVeth.network
[Match]
Name=host0
[Network]
Address=<containers ip address> example -> 192.168.1.100/24
Gateway=<gateway of that network> example -> 192.168.1.1
DNS=<DNS Servers address> example -> 9.9.9.9
#DHCP=yes -> or comment Address, Gateway and DNS and uncomment DHCP to assign the address automatically
systemd-networkd
:systemctl enable systemd-networkd
To let the container start that service, it needs to be booted (the previous command is more like chrooting). We achieve this by using the --boot
parameter. Additionally, we add the --network
parameter to start the container with a virtual network device.
systemd-nspawn --machine="Template" --directory=/var/lib/machines/template --boot --network
This will boot the container and display the login prompt. Logging in as root is not possible, so you must either create a user before booting into the container or proceed to section 4. Run container as a service.
useradd <your username here>
passwd <your username here>
As you may want to use your virtual network device for actual networking, further configuration is needed. Use, for example, Open vSwitch or a simple bridge device to connect the virtual network device to something.
It it possible to start a container as a service, for example to start it on boottime. There is a implementation through the systemd-nspawn@.service unit, but it requires to create override files to configure it. Our prefered way is to create a new servicefile, which contains all parameters we want to use for our container.
mkdir /var/lib/machines/my-first-container
rsync -avP /var/lib/machines/template/* /var/lib/machines/my-first-container/
sudo nano /etc/systemd/system/<your containers name here>.service
[Unit]
Description=<your containers name here>
After=network.target
Requires=network.target
[Service]
ExecStart=/usr/bin/systemd-nspawn --machine=<your containers name here> --directory=/var/lib/machines/my-first-container --boot
KillMode=mixed
Type=notify
Restart=always
[Install]
WantedBy=multi-user.target
If you want to use a virtual network device on your container add, --network
at the end of ExecStart=/usr/...
.
sudo systemctl start <your containers name here>.service
sudo systemctl enable <your containers name here>.service
machinectl
:sudo machinectl shell <your containers name here>
sudo machinectl
As the name suggests, a container typically does not have access to your host system. This can be modified to allow the container access to specific files or folders on your host system; for example, to provide additional storage space or grant the container access to your GPU.
--bind
parameter:systemd-nspawn --machine="Template" --directory=/var/lib/machines/template --bind=<path to your location>
systemd-nspawn --machine="Template" --directory=/var/lib/machines/template --bind=/home
This will mount the folder /home
to the same location within your container. If you wish to change the mount point inside your container, you can specify this by using a : between both paths.
/home
at /tmp/home
:systemd-nspawn --machine="Template" --directory=/var/lib/machines/template --bind=/home:/tmp/home
systemd-nspawn
is a extremly powerful tool. What we covered here are just the basics. Take a look at their man page, if you want to be amazed!