sudo apt install debootstrap systemd-container
mkdir -p ${HOME}/data/vcontainers
sudo debootstrap --arch amd64 --include=systemd-container,systemd,dbus stable ${HOME}/data/vcontainers/debian-stable http://mirrors.ucr.ac.cr/debian
mkdir -p ${HOME}/data/vcontainers
sudo debootstrap --arch amd64 --include=systemd-container,systemd,dbus jammy ${HOME}/data/vcontainers/ubuntu-jammy http://archive.ubuntu.com/ubuntu/
sudo rmdir /var/lib/machines
sudo ln -s ${HOME}/data/vcontainers/ /var/lib/machines
sudo systemd-nspawn -D /var/lib/machines/debian-stable -U --machine debian-stable
sudo systemd-nspawn -D /var/lib/machines/ubuntu-jammy -U --machine ubuntu-jammy
(This brings a root shell in guest OS)
Set root password:
passwd
Allow outside login:
echo 'pts/1' >> /etc/securetty
Logout from guest OS (Ctrl-d)
sudo machinectl enable debian-stable
sudo machinectl start debian-stable
sudo machinectl login debian-stable
(You still have to login as root)
(Now you can create users and stuff)
systemctl enable systemd-networkd.service
systemctl start systemd-networkd.service
vi /etc/hostname
(use a hostname name different from your host computer, something to recognize this guest machine appart from your host machine)
vi /etc/hosts
Change first line to:
127.0.0.1 localhost <newhostname here>
hostname <newhostname>
sudo systemctl enable systemd-networkd.service
sudo systemctl start systemd-networkd.service
Some times this is enough to be able to access internet. If not, follow method one or two, to set an static ip:
In the host copy file from /usr/lib/systemd/network/80-container-ve.network to /etc/systemd/network/ and edit it like this (set Address to your desired host-side ip):
# SPDX-License-Identifier: LGPL-2.1-or-later
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
# This network file matches the host-side of the virtual Ethernet link
# created by systemd-nspawn's --network-veth switch. See systemd-nspawn(1) for
# details.
[Match]
Name=ve-*
Driver=veth
[Network]
# Default to using a /28 prefix, giving up to 13 addresses per container.
Address=192.168.45.2/24
LinkLocalAddressing=yes
DHCPServer=yes
IPMasquerade=yes
LLDP=yes
EmitLLDP=customer-bridge
In the guest machine copy file from /usr/lib/systemd/network/80-container-host0.network to /etc/systemd/network/ and edit it like this (set Address to desired guest ip, gateway to host-side ip and DNS to a known working dns server):
[Match]
Virtualization=container
Name=host0
[Network]
#DHCP=yes
Address=192.168.45.10
Gateway=192.168.45.2
DNS=192.168.2.10
LinkLocalAddressing=yes
LLDP=yes
EmitLLDP=customer-bridge
[DHCP]
UseTimezone=yes
The above configuration didn't work in one computer (don't know why!). The ve-ubuntu-jammy network interface at the host side kept changing to a wierd second "scope link" ip. And then it lost connection
This configuration worked:
[Match]
Name=ve-*
Driver=veth
[Network] # Default to using a /28 prefix, giving up to 13 addresses per container.
Address=192.168.45.2/24
#LinkLocalAddressing=yes
#DHCPServer=yes
#IPMasquerade=yes
#LLDP=yes
EmitLLDP=customer-bridge
[Match]
Virtualization=container
Name=host0
[Network]
#DHCP=yes
Address=192.168.45.10
Gateway=192.168.45.2
DNS=192.168.2.10
#LinkLocalAddressing=yes
#LLDP=yes
#EmitLLDP=customer-bridge
[DHCP]
UseTimezone=yes
sudo systemctl restart systemd-networkd.service
systemctl restart systemd-networkd.service
iface eno1 inet manual
auto br0
iface br0 inet dhcp
bridge_ports eno1
/etc/systemd/nspawn/ubuntu-jammy.nspawn
[Network]
#Private=no
#VirtualEthernet=yes
Bridge=br0
This file is created in /etc/systemd/nspawn because the "bridge=" directive is privileged. IF this file is created on the machines directory, this directive is ignored
On guest create file /etc/systemd/network/80-container-host0.network
With content:
[Match]
Virtualization=container
Name=host0
[Network]
DHCP=yes
#Address=192.168.50.20
i#Gateway=192.168.50.2 #DNS=192.168.2.10 #LinkLocalAddressing=yes #LLDP=yes #EmitLLDP=customer-bridge
[DHCP]
UseTimezone=yes
Done!
apt update
apt-get install sudo
adduser <yourusername>
adduser <yourusername> sudo
sudo apt-get install software-properties-common
sudo add-apt-repository universe
sudo add-apt-repository multiverse
sudo add-apt-repository restricted
echo "deb http://security.ubuntu.com/ubuntu jammy-security main restricted" | sudo tee -a /etc/apt/sources.list
sudo apt update
sudo apt upgrade
There are some considerations necessary for supporting x application execution and nvidia gpu acceleration inside a nspawn container
Stop the machine (from host):
sudo machinectl stop debian-stable
Correct ownership of container files (from host):
sudo systemd-nspawn -D /var/lib/machines/debian-stable --private-users=0 --private-users-chown --machine debian-stable
(this takes a while, wait)
(don't restart machine)
Create a new file in /var/lib/machines with name: debian-stable.nspawn and add the following content.
[Exec]
PrivateUsers=0
Environment=DISPLAY=:0.0
[Network]
Private=yes
VirtualEthernet=yes
Make a link to /etc/systemd/nspawn:
sudo mkdir -p /etc/systemd/nspawn
sudo ln -s /var/lib/machines/debian-stable.nspawn /etc/systemd/nspawn/
Restart the machine:
sudo machinectl start debian-stable
Check that the owners are still correct after this:
sudo ls -alh /var/lib/machines/debian-stable/
Most files should have "root" as owner. If you se a (very big) number instead of "root", they there was a mistake while following the instructions.
Stop the machine (from host):
sudo machinectl stop debian-stable
Edit file /var/lib/machines/debian-stable.nspawn with like this:
[Exec]
PrivateUsers=0
Environment=DISPLAY=:0.0
[Network]
Private=yes
VirtualEthernet=yes
[Files]
BindReadOnly=/tmp/.X11-unix
BindReadOnly=/home/<yourusername>/.Xauthority
# Also necessary for Intel (maybe AMD):
Bind=/dev/dri
Bind=/dev/input
Bind=/dev/shm
#Bind=/dev/input/js0
(Remember to change your username there)
You can now start the machine and try to run a X application:
sudo machinectl start debian-stable
sudo machinectl login debian-stable
Login as your user in the container
Then install gpicview (very lightweight dependencies)
Inside container user console:
export DISPLAY=:0.0
gpicview
You should see the application running
stop the machine (from host)
Edit file /var/lib/machines/debian-stable.nspawn with like this:
[Exec]
PrivateUsers=0
Environment=DISPLAY=:0.0
[Network]
Private=yes
VirtualEthernet=yes
[Files]
BindReadOnly=/tmp/.X11-unix
BindReadOnly=/home/<yourusername>/.Xauthority
Bind=/dev/dri # Also necessary for Intel (maybe AMD)
Bind=/dev/nvidia0
Bind=/dev/nvidiactl
Bind=/dev/nvidia-modeset
Bind=/dev/nvidia-uvm
Bind=/dev/nvidia-uvm-tools
Bind=/dev/nvidia-caps
Bind=/dev/input
Bind=/dev/shm
#Bind=/dev/input/js0
Override nspawn services file:
sudo systemctl edit systemd-nspawn@debian-stable.service
Add the following at the beginning of edit window:
[Service]
DeviceAllow=/dev/nvidiactl
DeviceAllow=/dev/nvidia0
DeviceAllow=/dev/nvidia-modeset
DeviceAllow=/dev/nvidia-uvm
DeviceAllow=/dev/nvidia-uvm-tools
DeviceAllow=/dev/nvidia-caps
DeviceAllow=block-loop rwm
Inside container:
sudo systemctl edit console-getty.service
Put this:
[Service]
ExecStart=
ExecStart=-/sbin/agetty --noclear --autologin memeruiz --keep-baud console 115200,38400,9600 $TERM
Then this:
sudo systemctl edit container-getty@.service
Put this:
[Service]
ExecStart=
ExecStart=-/sbin/agetty --noclear --autologin memeruiz --keep-baud pts/%I 115200,38400,9600 $TERM
In Host OS:
sudo visudo
After the line that starts with "%sudo" add the following:
<your_user> ALL=(ALL:ALL) NOPASSWD: /usr/bin/machinectl login ubuntu-jammy
Adjust <your_user>
In Host OS:
alias vcuf="sudo machinectl login ubuntu-jammy"
With all this you can login passwordless to your container
In Guest OS:
For:
Add the following to .bashrc (.profile in Ubuntu):
alias datenow='date +%F_%T'
xterm() {
for i in $(eval echo "{1..$1}")
do
rxvt -bg gray30 -fg gray +sb -geometry 90x20 -fn "xft:monospace:size=10" &
done
}
ec() {
nohup emacs $@ &> /dev/null &
}
force_color_prompt=yes
PS1="\[\e]0;\u@\h: \w\a\]${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ "
# LS_COLORS='rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.wim=01;31:*.swm=01;31:*.dwm=01;31:*.esd=01;31:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:';
export LS_COLORS
# for setting history length see HISTSIZE and HISTFILESIZE in bash(1)
HISTCONTROL=ignoredups:ignorespace
# append to the history file, don't overwrite it
shopt -s histappend
HISTSIZE=1000000
HISTFILESIZE=2000000
export DISPLAY=:0.0
xrdb -merge ~/.Xresources
.Xresources:
Xft.dpi: 144
Xft.autohint: 0
Xft.lcdfilter: lcddefault
Xft.hintstyle: hintfull
Xft.hinting: 1
Xft.antialias: 1
Xft.rgba: rgb
!! Colorscheme
! special
*.foreground: #93a1a1
*.background: #141c21
*.cursorColor: #afbfbf
! black
*.color0: #263640
*.color8: #4a697d
! red
*.color1: #d12f2c
*.color9: #fa3935
! green
*.color2: #819400
*.color10: #a4bd00
! yellow
*.color3: #b08500
*.color11: #d9a400
! blue
*.color4: #2587cc
*.color12: #2ca2f5
! magenta
*.color5: #696ebf
*.color13: #8086e8
! cyan
*.color6: #289c93
*.color14: #33c5ba
! white
*.color7: #bfbaac
*.color15: #fdf6e3
Install gpicview and run it
Install mesa-utils and run glxinfo and glxgears
In guest install pulseaudio
In host in debian-stable.nspawn file add (in [Files] section):
BindReadOnly=/run/user/1000/pulse:/run/user/host/pulse/
PULSE_SERVER=unix:/run/user/host/pulse/native
default-server = unix:/run/user/host/pulse/native
This works even with pipewire (+ pulseaudio) in host
Capability=CAP_MKNOD
DeviceAllow=block-loop rwm
mknod /dev/loop0 b 7 0
sudo systemctl edit systemd-nspawn@debian-stable.service
DeviceAllow=/dev/fuse
Bind=/dev/fuse
[1] https://old.reddit.com/r/linux_gaming/comments/c50vsb/howto_run_steam_in_a_container_without_32bit/
[2] https://unix.stackexchange.com/questions/557293/how-can-i-make-a-device-available-inside-a-systemd-nspawn-container-with-user-na#597578
[3] https://gist.github.com/dirkakrid/3410fca1f9b3f37ce6cd0bccf77784ac#allow-the-service-to-access-the-block-device-files
[4] https://patrickskiba.com/sysytemd-nspawn/2019/03/21/graphical-applications-in-systemd-nspawn.html
[5] https://backports.debian.org/Instructions/
[6] https://wiki.archlinux.org/index.php/Systemd-nspawn#Use_an_X_environment
[7] https://wiki.archlinux.org/index.php/MATLAB#Matlab_in_a_systemd-nspawn
[8] https://liolok.github.io/Run-Desktop-Apps-with-systemd-nspawn-Container/
[9] https://ramsdenj.com/2016/09/23/containerizing-graphical-applications-on-linux-with-systemd-nspawn.html
[10] https://wiki.archlinux.org/title/Getty#Nspawn_console
[11] https://wiki.archlinux.org/title/Systemd-networkd#Network_bridge_with_static_IP_addresses
[12] https://github.com/systemd/systemd/issues/17607
[13] https://en.wikipedia.org/wiki/OS-level_virtualization