Emacs daemon as a runit service
So, you want to run an Emacs daemon as a runit service - and you also want to connect to it in your desktop session. Thanks to the new
--fg-daemon option in Emacs 26.x you now can! I'm going to describe how to set up the service, as well as
sudo rules for managing it without requiring a password each time. Read on for the exciting details!
Before you get too excited, there's a few prerequisites you'll need for this to be possible:
- Emacs 26+: As I've already mentioned, the
--fg-daemonoption was just added in Emacs 26 so you'll need that version.
- Runit: It doesn't have to be your PID1 (but maybe it should be?), but you of course need it running, doing its thing.
sudoas well as hotkeys for OpenBox.
The service "run" file is below:
#!/bin/sh export HOME=/home/hristos cd $HOME exec chpst -u hristos:hristos /usr/bin/emacs --fg-daemon=hristos-emacsd 2>&1
Nothing too crazy for a runit service here. I export my user's home directory as
$HOME, this way Emacs can find my
~/.emacs.d/ directory. I'm also naming the server's socket -- this way I can just pass that name to
emacsclient when I want to attatch:
$ emacsclient --socket-name=hristos-emacsd -c -n
This is nicer than having to give the path to the server's socket; easier for a human to reason about.
This is optional, but I prefer to add logging to all runit services. Doing this is standard fare for a runit service; Create a direcory called "log" in the root of your "emacs-daemon" service directory, and within that put a file called "run" with the below contents:
#!/bin/sh exec logger -t emacs-daemon
Make sure you have something like
rsyslog installed, and then you'll be able to find your "emacs-daemon" service logs in
/var/log/syslog or wherever your logs go. You can of course look at this output in the
*Messages* buffer, but what the hay am I right?
Now's the time to enable the service so that it can be used:
# ln -s /path/to/emacs-daemon /var/service/
Alter the paths to match where your things actually are, and then that's it. The Emacs daemon is now running.
As I showed above, you can now connect with a simple invocation of
emacsclient, but some aliases would be a lot better. For fish, I use this function:
function emacs command emacsclient --socket-name=hristos-emacsd -c -n $argv ; or \ zenity --error --no-wrap --text 'Failed to connect to the Emacs daemon!' ^/dev/null end
Now, anytime I invoke
emacs from the command line, I'll attach to the daemon. If it isn't running (and if you have zenity installed), then a message will pop up saying it was unable to connect. And for you OpenBox users out there, add the following in your
<keybind key="W-e"> <action name="Execute"> <startupnotify> <enabled>true</enabled> <name>Emacs</name> </startupnotify> <command>fish -c "emacs"</command> </action> </keybind>
Now you can open Emacs, and connect to your daemon with a simple press of "Meta+E"!
Although it's actually simple to close the daemon from within Emacs itself, thus prompting runit to relaunch a new process, it's still great to be able to use
sv to manage the service if need be. Even better, you can use sudo rules to allow you to do this without needing a password. Put the following in
Cmnd_Alias EMACSD_CMDS=/usr/bin/sv check emacs-daemon,/usr/bin/sv start emacs-daemon,/usr/bin/sv stop emacs-daemon,/usr/bin/sv restart emacs-daemon hristos ALL=(ALL) NOPASSWD: EMACSD_CMDS
Of course replace user names and commands as needed, but that's all you need.
For a long time I managed an Emacs daemon outside of runit (or any other service manager) and it was fine; One can run
emacsclient with the
--alternative-editor='' option and that will start the daemon if it's not already running. But having it start with your system, and having simple system-level controls for it is pretty useful and worthwhile considering the small amounts of effort required to implement.