User Tools

Site Tools


osinstallation:debian11runit

Debian 11 with runit as init system

What is an init system?

In unixoid operating systems - these include GNU/Linux, FreeBSD and OpenBSD - a program called “init” is always started as the first process. This is specified in the operating systems kernel. The init program in turn starts other programs, such as system services, and provides a login prompt at the end of the boot process.

To put it simply, starting a Unix-like system goes like this:

Bootloader (e.g. Grub) → Kernel (e.g. Linux kernel) → init → login prompt

A few years ago a change of the init system took place in most Linux distributions. The previously used init system “SysVinit” still has its origin in the primeval times of Unix. Services are started with SysVinit by shell scripts, which can become very complex. By the sequential processing of these scripts a system could need very long time to start. This seemed to be out of date. Because of this there were attempts to replace SysVinit by something more modern for some time.

Canonical tried it with Ubuntu with the “Upstart” system. Long before that, IT professor Daniel J. Bernstein (also known as “djb”) tried to improve the init system with his “daemontools”.

n 2010, Lennart Poettering - an employee at Red Hat - programmed the software “systemd”. Systemd should not only serve as an init system, but provide a complete framework, which serves the administration of Linux systems. Systemd not only starts services, but also provides sockets. In addition, systemd provides service with its own utilities, which are intended to replace the traditional Unix programs. For example, systemd-networkd, systemd-logind, systemd-journald (as a replacement for syslog), systemd-resolved (name resolution), systemd-timesyncd, etc. exist. And the number keeps growing.

In the last decade, systemd has become the default for most distributions. In Debian, it has been the default init system since version 8.

Why not use the default init system "systemd"?

Systemd is not only an init system. It performs a variety of tasks. If you consider the tasks that a modern desktop operating system has to perform, then it certainly makes sense to combine these tasks in an integrated system. In general, users are not interested in the single internal services that run on the computer. They want the computer to work and be fast. This is perfectly legitimate and systemd is fine for this purpose.

In IT, we often talk about “use cases” and the “desktop” use case is just one of many. In the area of system administration, it often comes down to keeping the system (server, router, etc.) stable and secure. Two basic Unix principles to achieve this are called

Keep it small and simple

and

Do one thing and do it well

This also has the purpose of avoiding too much complexity, because complexity is the enemy of security. One must acknowledge that systemd only pays little attention to these principles. It consists of over 1.2 million lines of code (as of 2019) and has - unsurprisingly - already made headlines due to spectacular security vulnerabilities.

Software which has such a fundamental significance in an operating system should therefore - if security is of importance - be “small and simple” in order to avoid security as far as possible.

What is runit?

As already said, there have been some attempts to modernize the init system during the last 20 years. Some of them found quite some popularity. The system “OpenRC” could be seen as an evolutionary development of SysVinit. This system is mainly used by Alpine Linux and Gentoo.

Based on the above mentioned daemontools from djb further systems developed, like s6 or runit. These daemontools-inspired init systems are similar in structure and use, but have different levels of complexity.

Runit is primarily designed for simplicity and has a small code base. This in itself is a good prerequisite to build a safe system. It consists of several small programs and knows per default 3 “stages”:

  • Stage 1 - System initiation
  • Stage 2 - Start services
  • Stage 3 - Shutdown or restart

The various programs are:

  • sv - to control services
  • chpst - control of a process environment
  • runsv - monitors a process (supervision) and optionally a logging service for this process.
  • svlogd - a simple but powerful logger,
  • runsvchdir - changes the service level
  • runsvdir - starts a supervision tree

In general an init system consists of

  • init / PID1 - Initiates everything else
  • a service manager - starts, stops and manages services
  • a supervisor - monitors running services

Runit is kept very minimal and has no full-blown service manager. For starting and stopping services sv is used.

  • Enable service ln -s /etc/runit/sv/service_name /run/runit/service
  • Disable service touch /run/runit/service/service_name/down
  • stop service sv down service_name # or sv stop service_name
  • start service sv up service_name # or sv restart service_name
  • restart service sv restart service_name
  • check service status sv status service_name
  • change runlevel (will stop all services and start all services in new runlevel) runsvchdir runlevel

Installation

I assume here a minimal system installation of Debian 11, done with a “netinst” ISO image. How to perform such a minimal installation of Debian is not part of this article. Important is only: in the software selection everything should be deselected.

After logging in to the system as root, at first the runit packages are installed

apt install runit runit-init

Since this replaces the init system, a confirmation prompt is issued, where Yes, do as I say! must be entered. Then the system is rebooted with reboot.

Then login again as root. Runit should already run, but some cleanup is needed. First uninstall systemd

apt –purge remove systemd

A login manager is required in most cases

apt install libpam-elogind

Finally, APT preferences are used to ensure that systemd does not sneak in again through the back door (through any dependencies)

cat << EOF >  /etc/apt/preferences.d/00systemd
Package: systemd
Pin: origin ""
Pin-Priority: -1
EOF

runit services

Now runit is running, but other than serving as init and starting and monitoring getty, it doesn't do much yet. Just like SysVinit it also starts services via scripts in /etc/init.d, but you could also have that with SysVinit. To take advantage of runit with supervision of services these services need to be started “runit style”. Fortunately, this is very simple.

Runit services, unlike SysVinit, usually only need a very short startup script. The services run in the foreground and must not fork into the background (i.e. no “daemonizing”). Also things like “start-stop-daemon” are no longer needed with runit.

rsyslogd

At first the service rsyslogd is “converted” to a runit service

# create runit service directory
mkdir /etc/sv/rsyslogd

# create "run" file
cat << EOF >/etc/sv/rsyslogd/run 
#!/bin/sh
exec /usr/sbin/rsyslogd -n
EOF

# make executable
chmod a+x /etc/sv/rsyslogd/run

# stop SysV rsyslogd
/etc/init.d/rsyslog stop

# disable SysV service
update-rc.d -f rsyslog remove

# enable runit service
ln -s /etc/sv/rsyslogd /etc/runit/runsvdir/default/

As you can see, creating a symlink from the service directory to the runsvdir default directory ensures that the service is set as “active” and also started immediately.

dbus

Dbus needs in addition to “run” another file called “check”.

mkdir /etc/sv/dbus

cat << EOF > /etc/sv/dbus/check
#!/bin/sh
exec dbus-send --system / org.freedesktop.DBus.Peer.Ping >/dev/null 2>&1
EOF

chmod a+x /etc/sv/dbus/check

cat << EOF > /etc/sv/dbus/run
#!/bin/sh
dbus-uuidgen --ensure=/etc/machine-id
[ ! -d /run/dbus ] && install -m755 -g 81 -o 81 -d /run/dbus
exec dbus-daemon --system --nofork --nopidfile
EOF

chmod a+x /etc/sv/dbus/run

/etc/init.d/dbus stop
update-rc.d -f dbus remove
# An error message followed, don't let it irritate you: insserv: FATAL: service dbus has to be enabled to use service elogind

ln -s /etc/sv/dbus /etc/runit/runsvdir/default/

elogind

mkdir /etc/sv/elogind

cat << EOF > /etc/sv/elogind/run
#!/bin/sh
sv check dbus >/dev/null || exit 1
exec /usr/lib/elogind/elogind
EOF

chmod a+x /etc/sv/elogind/run
update-rc.d -f elogind remove
ln -s /etc/sv/elogind /etc/runit/runsvdir/default/

To “runit-fy” additional services should not be a problem. You can also check the Arch-based distro Artix btw. This repo contains many examples of runit service scripts

Optional - Logging with runit

Runit comes with svlogd, a logging daemon that supports autorotate. For this purpose a directory log is created in the service directory. In this directory we create an executable script run, which starts svlogd. Here is an example

mkdir -p /etc/sv/<dienstname>/log

cat << EOF > /etc/sv/<dienstname>/log/run
#!/bin/sh

S="dienstname"
mkdir -p /var/log/runit/$S
chown _runit-log:adm /var/log/runit/$S
chmod 750 /var/log/runit/$S
exec chpst -u _runit-log svlogd -tt /var/log/runit/$S
EOF

chmod a+x /etc/sv/<dienstname>/log/run

In order for svlogd to log, the service must output its messages to stdout. Some services need an additional configuration for this.

Conclusion

I have demonstrated how to replace systemd on Debian 11 with the init service runit. Since runit is a proven, very lightweight and secure system, it is also possible to configure Debian quite a bit more securely and reliably with it. This is true for desktops as well as (ift not even more so) for servers. Supervision makes sure that services are monitored.

I will not hide the fact that runit reaches its limits in more complex scenarios. For this, the similar system s6, which is also based on djb's daemontools, might be more suitable, but it has a much steeper learning curve.

osinstallation/debian11runit.txt · Last modified: 2021/08/22 12:30 by senioradmin

Except where otherwise noted, content on this wiki is licensed under the following license: CC0 1.0 Universal
CC0 1.0 Universal Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki