Replacing Ubuntu's systemd with runit on my home server: what I learned

Introduction to Replacing systemd with runit

I’ve always been drawn to exploring alternative init systems, and in 2025, I decided to ditch Ubuntu’s default systemd for runit on my home server. My goal was to simplify the boot process and gain more control over the services running on my server. In this article, I’ll walk you through my experience with replacing systemd with runit, including the challenges I faced and the lessons I learned.

Why runit?

runit is a lightweight init system that provides a more traditional Unix-like experience. It’s designed to be easy to use and understand, with a focus on simplicity and flexibility. I chose runit because of its reputation for being reliable and easy to use, and because it aligns with my goal of simplifying my system’s boot process. Don’t bother with runit if you’re looking for a lot of hand-holding, though - it’s a more DIY approach to init systems.

Preparing for the Switch

Before making the switch, I backed up my system and made a list of the services currently running on my system. This included services like ssh, nginx, and mysql. I’ve seen this go wrong when people don’t plan ahead, so take the time to review your services and make sure you know what you’re getting into.

Installing runit

To install runit on my Ubuntu system, I used the following command:

sudo apt-get install runit

This installed the runit package and its dependencies. The real trick is to make sure you have all the necessary dependencies installed before you start configuring runit.

Configuring runit

After installing runit, I needed to configure it to manage the services on my system. runit uses a simple and intuitive configuration format, with each service defined in a separate directory. For example, to configure the ssh service, I created a directory called /etc/sv/ssh and added the following files:

# /etc/sv/ssh/run
#!/bin/sh
exec sshd -D
# /etc/sv/ssh/finish
#!/bin/sh
pkill sshd

These files define the run and finish scripts for the ssh service, which are used to start and stop the service. In practice, you’ll want to make sure you have a solid understanding of how these scripts work before you start creating your own.

Converting systemd Services to runit

To convert my existing systemd services to runit, I needed to create new configuration files for each service. This involved creating a new directory for each service, and adding the necessary run and finish scripts. For example, to convert the nginx service, I created a directory called /etc/sv/nginx and added the following files:

# /etc/sv/nginx/run
#!/bin/sh
exec nginx -g "daemon off;"
# /etc/sv/nginx/finish
#!/bin/sh
pkill nginx

I repeated this process for each of the services on my system, creating new configuration files for each one. This is where people usually get burned - they don’t take the time to properly test their services after converting them to runit.

Booting with runit

After configuring runit and converting my systemd services, I needed to update my system’s boot process to use runit instead of systemd. To do this, I updated my system’s boot loader configuration to use the runit init system. On Ubuntu, this involves editing the /etc/default/grub file and adding the following line:

GRUB_CMDLINE_LINUX_DEFAULT="init=/sbin/runit"

I then updated my system’s boot loader configuration using the following command:

sudo update-grub

This updated my system’s boot loader to use runit as the init system. I usually start with a test boot to make sure everything is working as expected before I make any major changes to my system.

Troubleshooting

During the transition to runit, I encountered a few issues that required troubleshooting. One of the main issues I faced was getting the ssh service to start properly. After some investigation, I discovered that the issue was due to a missing dependency in the ssh service configuration file. To fix this, I added the following line to the /etc/sv/ssh/run file:

#!/bin/sh
exec sshd -D

I also had to update the /etc/sv/ssh/finish file to properly stop the ssh service:

#!/bin/sh
pkill sshd

With these changes, the ssh service started properly and I was able to connect to my system remotely.

Security Considerations

When replacing systemd with runit, it’s essential to consider the security implications of the change. One potential security risk is the use of custom configuration files, which can introduce vulnerabilities if not properly validated. To mitigate this risk, I made sure to carefully review and test each configuration file before deploying it to my system. I also ensured that all services were properly configured to use secure protocols and authentication mechanisms.

Lessons Learned

Replacing systemd with runit on my home server was a valuable learning experience. I gained a deeper understanding of the init system and how it manages services on my system. I also learned the importance of careful planning and testing when making significant changes to my system’s configuration. If you’re considering replacing systemd with runit, I recommend taking the time to thoroughly research and test the process before making the switch.

For more information on runit and its configuration, I recommend checking out the official runit documentation on GitHub. Additionally, the Arch Linux wiki has a comprehensive guide to using runit on Arch Linux systems.


See also