+++ title = "User Services With Systemd" date = "2024-08-18T19:05:10-04:00" tags = ["systemd","selfhosting"] +++ # Your very own `systemd` Recently, I've started using `systemd` order to manage personal services on my servers. Before that, I had set up classic system-wide unit files or, for more ad-hoc services, started the process inside of a `screen` session, then detaching, hoping the process didn't crash overnight. Using a user instance of `systemd` is way better, since you get stuff like `journalctl` to view logs and `RestartAlways` keep things running after random crashes. Plus, all configuration now lives in `$HOME` making it easy to edit and back up. In this post, I will show you how to set this up on any modern Debian-based system (or any distro that uses `systemd`, really). _Debian 12.6 (bookworm) was used at the time of writing this post._ # Caveats There are a few things to note with this approach: * User units **cannot** depend on system-wide units, or vice versa. For example, your user service cannot depend on system-wide `redis-server`. To specify dependencies between your services, you'll need to run all of those dependencies as user services. * User units are run without privileges so naturally they can't do `root` things like edit files outside of `$HOME` and listen below port `1024`. * Environment variables set in `~/.zshrc`, `~/.bashrc`, etc are not inherited. See the [environment variables section](https://wiki.archlinux.org/title/Systemd/User#Environment_variables) for more information on how to set/import environment variables for user units. # Getting Started ## Enable linger for your user By default, `systemd` user instances are only started after the first login of that user then killed once their last session is closed. This behavior makes sense in a desktop environment but not so much for a server environment where you typically want your daemons running at all times. In order to change this behavior, you have to enable _linger_ for your user by running the following: $ loginctl enable-linger You can verify if lingering is enabled by ensuring the column for `LINGER` says `yes` for your user when running: $ loginctl list-users ## Create configuration directory The [unit files](https://www.freedesktop.org/software/systemd/man/latest/systemd.unit.html) for our services will live in `$HOME/.config/systemd/user/`. Ensure it's created using by using `mkdir -p`, like so: $ mkdir -p $HOME/.config/systemd/user/ ## Setting up an example service We can now place this `example.service` unit in `$HOME/.config/systemd/user/`: ``` [Unit] Description=Example Service [Service] Restart=always RestartSec=1s WorkingDirectory=/home/me/my-service-dir ExecStart=racket hello-world-server.rkt [Install] WantedBy=default.target ``` ## Reload unit files Just like system-wide `systemd`, if you edit or create new unit files for your user, you'll need to reload your copy of `systemd` by running `systemctl daemon-reload`, like so: $ systemctl --user daemon-reload ### Start service on boot This starts `example` as soon as your copy `systemd` is launched (which should be at boot, since we enabled lingering): $ systemctl --user enable example ### Starting, Stopping and Status You can now run the same `systemctl` commands you are used to, except they are run as your user (instead of `root`) and now require the `--user` argument: $ systemctl --user start example $ systemctl --user stop example $ systemctl --user status example $ systemctl --user restart example ### Logs Similar to `systemctl`, you'll need to pass `--user` to `journalctl`: $ journalctl --user --unit=example # More information You can read more about this feature on the [Arch Linux Wiki: systemd/User](https://wiki.archlinux.org/title/Systemd/User).