For my NAS, I've been using a homebrew Gentoo install maintained in a virtual machine, which is then regularly imaged to a rotating pair of thumbdrives.
I've done a number of things to make this a bit more convenient, which I realized I hadn't written up.
nas.target
This one I did write-up before, but I mention it briefly here because it's important to the more resent steps.
In short, systemd replaces the legacy init concept of "runlevels" with "targets". There are some well-known runlevels that map to traditional concepts, such as "single", "multi-user" and "graphical".
For this setup, I've added nas.target
, and configured systemd to make that the default target on boot.
This allows me to segregate all the services relevant to running as a NAS "for real" on the network from the very minimal set I need to maintain packages (really, just sshd).
virtual boot overrides
In my simple theme for machines, my firewall is 'fire', the wifi is 'air', my personal machine is 'water', and the NAS is 'earth'.
To avoid conflicts in local dns, when I start the virtual copy of earth for maintenance, I rename its hostname to 'terra'.
For a few years, my process for starting the vm was the following:
- launch vm
- jump into grub
- 'e'dit the entry boot options
- add 'single' to the linux kernel command line
- wait for single-user prompt
- root password
echo terra > /proc/sys/kernel/hostname
systemctl isolate multi-user
- wait for sshd launch
- ssh in for maintenance in my normal terminal
This was always a pain in the ass.
ConditionVirtualization=true hostname setting
I've very lazily learned how to write systemd units, and while solving some other problem, I became aware of the Condition*
… uh … conditions.
This led to /etc/systemd/system/terra-hostname.service
:
[Unit]
Description=Set the "earth-ng" hostname to "terra" when running virtualized
ConditionVirtualization=true
[Install]
WantedBy=sysinit.target
[Service]
Type=oneshot
ExecStart=/root/bin/set-terra-hostname
Life was suitably improved; now I only needed to edit the grub kernel command line.
I'm not sure when it happened, and I think it was actually quite recently, but at some point systemd-unit
became a kernel command line option. So now all I needed to do is edit the command line to add systemd.unit=multi-user.target
, and off it goes. Unless I misspell systemd, which I regularly do.
Ideally, I would find a way within systemd maybe with ConditionVirtualization
to dynamically target multi-user
rather than nas
, and I wouldn't need to do anything. But, until then…
For every identified kernel, grub-mkconfig
already creates two entries: the normal boot and a 'recovery' entry with the 'single' option added … why can't it just add a third entry per.
grub
Looking at /etc/grub.d/10_linux
, it's pretty obvious where the change should be:
# in linux_entry:
if [ x$type != xsimple ] ; then
case $type in
recovery)
title="$(gettext_printf "%s, with Linux %s (recovery mode)" "${os}" "${version}")" ;;
+ multi_user)
+ title="$(gettext_printf "%s, with Linux %s (multi-user.target)" "${os}" "${version}")" ;;
*)
title="$(gettext_printf "%s, with Linux %s" "${os}" "${version}")" ;;
# in the main function:
linux_entry "${OS}" "${version}" advanced \
"${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
+ linux_entry "${OS}" "${version}" multi_user \
+ "${GRUB_CMDLINE_LINUX} systemd.unit=multi-user.target ${GRUB_CMDLINE_LINUX_DEFAULT}"
if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then
linux_entry "${OS}" "${version}" recovery \
"single ${GRUB_CMDLINE_LINUX}"
fi