Private runit on Mac OS X El Capitan with homebrew

Runit is a great service supervisor that is used on some Linux distributions. It has been praised in some blogs ([1], [2]) for its simplicity and robustness.

On Mac OS X, we have launchd as init/service supervisor and the goal is not to replace it with runit, but to launch runit at startup and use it to start other services. In this blog, we use homebrew to install runit and configure it in order to start user specific private services.

First install runit with brew install runit. The installation will warn you that runit has just been installed but not enabled with the following message.

This formula does not install runit as a replacement for init.
The service directory is /usr/local/var/service instead of /service.
To have runit ready to run services, start runsvdir:
    runsvdir -P /usr/local/var/service
Depending on the services managed by runit, this may need to start as root.

The original runit distribution contains some files and help to configure launchd to load runit at startup. But these instructions (e.g. like creating a file in /sbin) are not compatible with Mac OS X El Capitan (as e.g. the folder /sbin is protected [3], we present here an alternative launchd configuration which consists of modified files from the runit distribution [4].

  1. Create a folder /usr/local/sbin;
  2. Run brew doctor and fix the warnings;
  3. Create an executable file runsvdir-start in /usr/local/sbin with the following content: runsvdir-start
  4. (Sudo)create a file org.smarden.runit.plist in the folder /Library/LaunchDaemons with the following content: org.smarden.runit.plist.
  5. Load runit in launchd with the following command:

     sudo launchctl load /Library/LaunchDaemons/org.smarden.runit.plist
    
  6. Run runit with sudo launchctl start org.smarden.runit

Now you have a running runit that will start services for the folder /usr/local/var/service. To allow individual users to run private services, follow these steps:

  1. Create a folder ~/Library/service that will hold private services;
  2. Create a folder /usr/local/var/sv;
  3. Create a service folder runsvdir-<username> in the folder /usr/local/var/sv
  4. Create the run executable file of the service folder runsvdir-<username> with the following content:

     #!/bin/sh
     exec 2>&1
     exec chpst -u<username> runsvdir /Users/<username>/Library/service
    
  5. Load it in runit via the following symlink command:

     ln -s /usr/local/var/sv/runsvdir-<username> /usr/local/var/service
    
  6. Set the environment variable SVDIR to point to the private service folder ~/Library/service.

Now you can symlink services into your private service folder ~/Library/service to let runit start and supervise them.

Footnotes

[1]: Use runit! by Mike Perham

[2] Process Supervision: Solved Problem by jtimberman

[3]: Ars Technica, El Capitan review

[4]: runit - use with traditional init