Running a User Service with Systemd on Fedora 33
Why Run a User Service under systemd
I have a small project on Github, netmon, that I have been using to learn about writing golang web applications. The Go web application uses a Python-based program called speedtest-cli to roughly measure network connection speeds using speedtest.net’s APIs and services.
I have been running netmon
on a few older Raspberry Pi computers,
a Raspberry Pi 1 Model
B+ and a
Raspberry Pi 2 Model
B. The RPi 1 has
been running Raspbian (now Raspberry Pi
OS) and the RPi 2 has
been running Ubuntu MATE (16.04). netmon
would run on these
machines for days, weeks, months and I was lazy, until recently, and would just
start up the program by hand, put the software in the background, and let it
run. Eventually, I decided to run the service using
systemd so that it would run automatically every time the
system restarted. I created the systemd
service files and, for convenience,
ran the software from my home directory where I could modify it easily. Ubuntu
let me run the software from my home directory despite being a system-level
systemd
service. I should note netmon
was run as unprivileged user since it
didn’t need special permissions (mainly just network access).
In the last few weeks, the Ubuntu MATE machine started having issues, restarting
regularly. So, I rebuilt it using Fedora Server 33 for 32-bit
Arm. I tried using the systemd
service files
that I had created before for Ubuntu, but they didn’t work because
SELinux was preventing the software from running.
This makes sense because the SELinux setup under Fedora (and other Red
Hat-related distributions) are setup so that system service executables can’t
run from a user’s home directory–only specific system directories.
While I could have just installed netmon
in a system directory, I preferred
having the binary in my home directory to make it easier for me to update and
modify. As noted above, it didn’t really need to run as a privileged user, so I
decided to figure out how to run the program as a user-level systemd
service.
Of course, the catch was that, while I have done system-level services with
systemd
, I hadn’t done any as a user-level service.
Setting Up the Service
I found a few useful pages on the topic, including a page on the Arch
Wiki. As noted on the Arch
Wiki page, a user can put their own systemd
units (i.e., service files) in
~/.config/systemd/user/
. Once the unit file has been created, you can run the
service using systemctl --user enable myservice
, where myservice
is the name
of the service installed in ~/.config/systemd/user/
.
So for netmon
, I took the system-level systemd
unit file and modified it
slightly, removing the User
declaration in the [Service]
section of the file
since the software will be running as me since it is a user-level service. I
then placed it in ~/.config/systemd/user
and ran systemctl --user enable netmon
and systemctl --user start netmon
to try to start the service.
The problem I ran into next is that the PATH
environment variable in my
~/.bashrc
was not being used by the service, so it couldn’t find
speedtest-cli
. In the Environment Variable section of the Arch Wiki
page on user-level systemd
, it suggests creating a .conf
file with the
NAME=VAL
pairs defining the needed environment.
In my case, I created a file called netmon.conf
file in
~/.config/systemd/user
with the needed PATH
defined (e.g.,
PATH=/home/myname/bin
).
Finally, systemd
user services don’t continue past a user’s login session.
The Automatic start-up of systemd user
instances
section on the same Arch Wiki page describes how to make the user service run
without the user logged in and at system startup time. It comes down to running
the following command for the specific user:
loginctl enable-linger username
With all of that in place, I was able to get the user-level service running much
like a system-level service using systemd
.