Debian systemd-nspawn server

From campisano.org
Jump to navigation Jump to search

Debian systemd-nspawn server

This page shows how to configure an independent 'guest' Debian server inside whatever gnu/linux host system running. The only requisite is that the host machine must run a gnu/linux with the same arch (for instance amd64) of the guest system.

Nowadays, a easy and well documented way to do such thing using an official Debian docker image and installing the docker daemon service in the host machine. However, a solution that provides a minor overhead for disk space and memory consumption is the use of the native systemd system. Such solution is the scope of this article. Note that a more crude solution is the use of the old good friend chroot command that still perform a good job but just for filesystem isolation. A tutorial using chroot is avaliable here.

Prerequisites

To start, we need to create a minimal Debian system root folder. This can be done following the Debootstrap tutorial that generates a Debian root folder compressed in a tar.gz file. In the same tutorial there are instruction to extract and configure the Debian system root folder in the host machine.

So, move the compressed tar.gz file in the host machine and configure it following the Debootstrap tutorial itself.

Configure the 'guest' system to start at the 'host' bootstrap

Now we need to configure our host system to boot the Debian guest system at startup:

########################################
#### Configure container to start at host bootstrap

export BASE_PATH=/srv
export DEST_DIR=DEBIAN_buster_amd64
export CONTAINER_NAME=DEBIANGUEST       # note, no dashes or hyphens allowed in the container name, 

# Enable the "machines" target so all of the containers we create are able to be started at boot via a service call. While the services may be started and enabled, if this target is not added the nspawn containers will not auto-boot.
systemctl enable machines.target

# Create a new boot systemd service
systemctl enable systemd-nspawn@${CONTAINER_NAME}.service

# Customize the container startup
# note, the first empty ExecStart= is required
mkdir -p /etc/systemd/system/systemd-nspawn@${CONTAINER_NAME}.service.d/
cat > /etc/systemd/system/systemd-nspawn@${CONTAINER_NAME}.service.d/override.conf << EOF
[Service]
ExecStart=
ExecStart=/usr/bin/systemd-nspawn --keep-unit --boot --link-journal=try-guest --directory=${BASE_PATH}/${DEST_DIR} --machine ${CONTAINER_NAME}
EOF

systemctl daemon-reload

# start now
systemctl start systemd-nspawn@${CONTAINER_NAME}.service
systemctl status systemd-nspawn@${CONTAINER_NAME}.service

# enter
machinectl list   # to see the container name
machinectl login ${CONTAINER_NAME}

Add a custom services in the 'guest' system

Save it and put it to work!

chmod 0750 iptables_SSHlimit.sh
mv iptables_SSHlimit.sh /etc/init.d

cat > /etc/systemd/system/iptables_SSHlimit.service << EOF
[Unit]
Description=Firewall rules to limit ssh incoming connections

[Service]
Type=simple
RemainAfterExit=yes
ExecStart=/etc/init.d/iptables_SSHlimit.sh start
ExecStop=/etc/init.d/iptables_SSHlimit.sh stop

[Install]
# Installs a hook to use this unit file when the system boots or shuts down
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable iptables_SSHlimit.service
systemctl start iptables_SSHlimit.service 
systemctl status iptables_SSHlimit.service

Configuring network details (to be completed)

########################################
#### HOST SIDE
# setup macvlan bridge

ip addr

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP group default qlen 1000
    link/ether 06:00:30:b5:ad:9a brd ff:ff:ff:ff:ff:ff
    inet 172.31.20.253/20 brd 172.31.31.255 scope global dynamic eth0
       valid_lft 2459sec preferred_lft 2459sec
    inet6 fe80::400:30ff:feb5:ad9a/64 scope link
       valid_lft forever preferred_lft forever

#ip link del macvlan1
ip link add macvlan1 link eth0 type macvlan mode bridge
ip addr add 10.0.0.1/24 broadcast 10.0.0.255 dev macvlan1
ip link set macvlan1 up

systemd-nspawn --boot --directory=${BASE_PATH}/${DEST_DIR} --private-network --network-macvlan=macvlan1 --machine debian
ip addr

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: mv-macvlan1: <BROADCAST,MULTICAST> mtu 9001 qdisc noop state DOWN group default qlen 1000
    link/ether 66:4a:4f:c5:8d:4f brd ff:ff:ff:ff:ff:ff link-netnsid 0

ip addr add 10.0.0.2/24 broadcast 10.0.0.255 dev mv-macvlan1
ip link set mv-macvlan1 up
ip route add default via 10.0.0.1 dev host0


# Note: use root as user, and run 'shutdown -h now' to quit
## configure the system in a second terminal
ip link
#1: lo:                                 # loopback, not to use
#2: enp2s0f0:                           # unused ethernet in this example
#3: wlp3s0b1:                           # internet output interface in this example
#26: ve-DEBIAN_stre@if2:                # guest interface in this example
#
# set a arbitrary ip for the guest interface in the host side
ip addr add 10.0.0.1/24 broadcast 10.0.0.255 dev ve-DEBIAN_stre
ip link set dev ve-DEBIAN_stre up
# enable the packed forward
sysctl -w net.ipv4.ip_forward=1
sysctl -w net.ipv6.conf.default.forwarding=1
sysctl -w net.ipv6.conf.all.forwarding=1
# configuring the forward output
iptables -t nat -A POSTROUTING -o wlp3s0b1 -j MASQUERADE
iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
# adding output forward for the guest interface in the host
iptables -A FORWARD -i ve-DEBIAN_stre -o wlp3s0b1 -j ACCEPT
########################################
#### GUEST SIDE
ip link
#1: lo:                                 # loopback, not to use
#2: host0@if26:                         # host interface in this example
#
# set a arbitrary ip for the host interface in the guest side
ip addr add 10.0.0.2/24 broadcast 10.0.0.255 dev host0
ip link set dev host0 up
# define the host interface as default gateway
ip route add default via 10.0.0.1 dev host0
# configure a name server
echo nameserver 8.8.4.4 > /etc/resolv.conf
ping 8.8.4.4
########################################

References