Containerize ZNC with systemd-nspawn
Published on
On my previous server, I had an IRC client (weechat) running in a screen session. I recently migrated this setup to a ZNC bouncer running on my server + weechat running on my laptop, mainly to avoid network lags through SSH and to have a better desktop integration (notifications, etc.).
My server hosts my e-mails, important and confidential documents (among other things) and I always thought that running an always connected IRC client on the same machine was a bad idea.
So in the same time I got rid of my weechat+screen to migrate to ZNC, I had a look at systemd-nspawn, also known as systemd containers. It’s actually pretty much like LXC containers, but managed with the systemd logic in mind.
Here is a quick tutorial of how I containerized ZNC into a systemd container on a Debian stretch system:
-
First, install systemd-container and debootstrap packages:
# apt install systemd-container debootstrap -
Create directories used by
systemd-container(which aren’t create on install):# mkdir /var/lib/machines/ /etc/systemd/nspawn//var/lib/machines/ will host the containers’ hierarchy and containers unit files will be stored into /etc/systemd/nspawn/.
-
Install a Debian system + znc package using
debootstrapinto /var/lib/machines/znc/:# cd /var/lib/machines/ # debootstrap --include znc stretch znc -
To make the container start on boot, you have to enable the corresponding systemd-nspawn instance and the machines target (which will start all enabled instances of systemd-nspawn unit:
# systemctl enable systemd-nspawn@znc machines.target -
At this stage, your container is ready. You can start your container (run its init process) with:
# systemd-nspawn -D /var/lib/machines/znc/Or execute a command in the container:
# systemd-nspawn -D /var/lib/machines/znc/ hostnamesystemd-nspawn comes with the
machinectlcommand which allows you to easily manage your containers:# machinectl [list|list-images|start|stop|status|…]See its man page for all supported sub-commands and options.
-
Now, let’s configure some few extra stuff to run ZNC. Create a dedicated user in the container:
# systemd-nspawn -D /var/lib/machines/znc/ useradd -u 1002 -g 1002 -m znc -
And customize the container’s options by putting a config file into /etc/systemd/nspawn/:
[Exec] # Don't start the init process inside the container, instead execute # `znc` Boot=off Parameters=/usr/bin/znc --foreground # Drop all default capabilities: the container will run with no # capabilities, ZNC doesn't need any DropCapability=CAP_CHOWN CAP_DAC_OVERRIDE CAP_DAC_READ_SEARCH CAP_FOWNER CAP_FSETID CAP_IPC_OWNER CAP_KILL CAP_LEASE CAP_LINUX_IMMUTABLE CAP_NET_BIND_SERVICE CAP_NET_BROADCAST CAP_NET_RAW CAP_SETGID CAP_SETFCAP CAP_SETPCAP CAP_SETUID CAP_SYS_ADMIN CAP_SYS_CHROOT CAP_SYS_NICE CAP_SYS_PTRACE CAP_SYS_TTY_CONFIG CAP_SYS_RESOURCE CAP_SYS_BOOT CAP_AUDIT_WRITE CAP_AUDIT_CONTROL # Start `znc` as znc User=znc # Those 2 options aren't supported by the version of systemd shiped with Debian stretch. Ephemeral=on makes the container discard on shutdown any modification made during its runtime (Docker style) and NoNewPrivileges ensures that the code executed inside the container won't be able to gain greater privileges (with setuid bit for instance) #Ephemeral=on #NoNewPrivileges=on # Use private user namespace (equivalent to LXC's unprivilegied mode) PrivateUsers=on [Files] # Mount my .znc configuration directory onto the container (with write access) and the znc.pem containing the private key, certificates chain and DH param (read-only) Bind=/home/romain/.znc/:/home/znc/.znc/ BindReadOnly=/var/lib/acme/live/irc.univers-libre.net/combined:/home/znc/.znc/znc.pem [Network] # Use the same network stack as the host VirtualEthernet=noThis file will automatically be read by
systemd-nspawnbefore starting the container. All these options can be specified as commandline parameters tosystemd-nspawnas well.
Resources: