Skip to content

Instantly share code, notes, and snippets.

@tgulacsi
Last active April 8, 2023 05:29
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save tgulacsi/61f106d2458c9987dae5 to your computer and use it in GitHub Desktop.
Save tgulacsi/61f106d2458c9987dae5 to your computer and use it in GitHub Desktop.
Using runit as a supervisor for Caddy

Supervisors

A supervisor's main task, is to start a specified process (in a specified environment), watch it running, and do something when it ends - usually based on the exit code.

From my experience, the environment setup can be a complex task (consult some config management for the required ports, actualize the config file from the central config management...), and this is where the most featureful supervisor (systemd, AFAIK) falls short:

  • it can setup & manage the listening sockets, and pass it to your app (if it can accept it - not hard, just have to be ready for it),
  • can set environment variables - but just with static values
  • and can run preparation jobs - but just for 30 seconds!

and my biggest complaint against it is the strict, quite restricted format, where writing simple scripts is hard

  • especially with those unhelpful "bad quoting" error messages.

This is where I feel another big disadvantage: debugging. I don't know a way to test the systemd service other than start it, call systemctl status my.service couple of times, maybe journalctl -f in another window.

Runit is a very simple supervisor, composed by a handful programs, in the UNIX philosophy:

  • svlogd logging daemon writes lines from its stdin into files in a specified directory, rotates & compresses & mails as defined in the "config" file in that directory.
  • chpst helps running yout program as the specified user, maybe holding a lock on the specified file, even setting the program's name as you wish.
  • runsv runs the "run" program (usually a shell script which sets up the environment, then execs your app), calls the "finish" (if exist) on exit, then restarts after a second sleep.
  • sv sends commands to runsv by writing one letter into the supervise/ctl file set SVDIR so you won't have to specify it to sv: export SVDIR=/etc/service; sv restart caddy will restart /etc/service/caddy.
  • runsvdir watches a directory, and starts runsv on each subdirectory - so it can supervise multiple programs.

Comparing to systemd, it can't do the socket activation magic, but

  • can set up complex environment - it's just the run shell script
  • can debug it easily: just call ./run as your runsv would!

Caddy is a very simply usable web server, so doesn't need too much, the simplest run file can be:

#!/bin/sh
exec /usr/local/bin/caddy -conf=/etc/Caddyfile

And a more complex:

#!/bin/sh
exec chpst -b my-web-server -u www-data -L /var/run/caddy.lock \
  /usr/local/bin/caddy -conf=/etc/Caddyfile

Sorry, Caddy is too simple to force writing some big fat setup script :)

Now I start runsvdir by my init daemon (upstart, systemd, OpenRC, SysV - what you have), and let runit do its job.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment