In my efforts to migrate my server to a new machine and a different OS, I found myself in need of replacing FreeBSD Jails with an analogous way of containerization. My distaste for Docker outweighed my distaste for systemd, so I tried systemd-nspawn. With Jails and ezjail it was fairly easy to set up a container with a separate, static IP address to which I could redirect particular traffic, either by port or (in case of HTTP) name. I’m not completely sure about my solution with nspawn yet, but it seems ok. I switched the host network configuration from networking.service to systemd-networkd and I’m using the trick described here to keep other parts of the network setup simple. It uses the default virtual ethernet interfaces and runs a DHCP server on the host with a pool of one - thus effectively forcing a static IP. I’m using it for the same purpose as described in the link - to proxy by name via nginx. You don’t necessarily need that for redirection by port, you can just use “port mapping” there.
It makes sense to configure some resource limits for CPU and the like, depending on the application. But other than that, below is my script to create a new nspawn machine for now. It takes a machine name, installs Debian stable and sets up networking.
#!/bin/bash set -eu if [ "$#" -ne 1 ]; then echo "Need machine name" exit 1 fi name="$1" path="/var/lib/machines/$name" if [[ -e "$path" ]]; then echo "Machine already exists" exit 2 fi echo "Bootstrapping debian stable to $path" debootstrap --include=systemd,dbus stable "$path" echo "Enable networkd in container" systemd-nspawn -M "$name" --as-pid2 rm /etc/hostname systemd-nspawn -M "$name" --as-pid2 systemctl enable systemd-networkd echo "Set root password" systemd-nspawn -M "$name" --as-pid2 passwd root # find out which virtual device name systemd uses machinectl start "$name" ip a read -p "Virtual ethernet name? " veth # set a "static" ip 192.168.x.y with # host y = 1 and machine y = 2 # by running a DHCP server with pool size 1 numberOfMachines=`ls /var/lib/machines/ | wc -l` machinectl stop "$name" networkdpath="/etc/systemd/network/50-$name.network" cat <<EOF >"$networkdpath" [Match] Name=$veth Driver=veth [Network] Address=192.168.$numberOfMachines.1 LinkLocalAddressing=ipv4 DHCPServer=yes IPMasquerade=ipv4 LLDP=yes EmitLLDP=customer-bridge IPv6SendRA=no [DHCPServer] PoolOffset=2 PoolSize=1 EOF echo "Restarting networkd and starting machine" systemctl restart systemd-networkd sleep 2 machinectl start "$name" machinectl enable "$name" # list all machines with IP address machinectl