Systemd services and timers

Posted .

These are some notes on systemd services. Once in a blue moon I have to add or modify a service on my machine and every single time I have to look up how this works. So I decided to write up some basic notes for future reference.

Here are the docs on [Unit], [Install] and [Service].

Creating a new service

Create a new service using:

sudo systemctl edit --force --full $name

Here’s a basic service configuration

[Unit]
Description= #A short description of the service.
Requires= #Some unit

[Service]
Type= #A type
Exec= #Command that starts the service
ExecStart= #Optional start only command
ExecStop= #Optional stop only command
PIDFile= #Optional pidfile
User= #Optional user to execute command as

[Install]
RequiredBy= #Some unit, often multi-user.target

Targets

Targets can be either Requires or Wanted by a unit.

You can list targets using:

systemctl list-units --type=target

Some commonly used targets.

basic.target
loaded active active Basic System
cryptsetup.target
loaded active active Local Encrypted
graphical.target
loaded active active Graphical Interface
local-fs.target
loaded active active Local File Systems
multi-user.target
loaded active active Multi-User System
network.target
loaded active active Network

Types

Commonly used service types.

simple
default type. Assumes the process itself does not fork and that it will be available immediately to services that depend on it when forked by systemd.
exec
similar to simple except it waits with starting depending services until the main executable is started.
forking
a service that forks itself, for executables that run in the background on their own. Provide PIDFile=.
oneshot
a non-service that does not run in the background. For executables that do their thing and then stop. Provide RemainAfterExit=yes if systemd needs to consider it running after the main processes exits.

Example services

[Unit]
Description=ProtonVpn
Wants=network-online.target
After=network.target network-online.target

[Service]
Type=oneshot
ExecStart=/usr/bin/sudo /usr/bin/protonvpn c --p2p
ExecStop=/usr/bin/sudo /usr/bin/protonvpn d
RemainAfterExit=yes
User=$user

[Install]
RequiredBy=multi-user.target
[Unit]
Description=Pi-hole blacklist
Wants=pihole-FTL.service

[Service]
Type=oneshot
ExecStart=/usr/local/bin/pihole -b example.com
ExecStop=/usr/local/bin/pihole -b -d example.com
RemainAfterExit=yes

[Install]
RequiredBy=multi-user.target

Timers

Docs for [Timer].

Create using, it should have the same name as the service it controls:

sudo systemctl edit --force --full $name.timer

Here’s a basic timer configuration

[Unit]
Description= #A short description of the timer.

[Timer]
OnCalendar= #Sets the time of execution

[Install]
RequiredBy=timers.target

The OnCalendar has the following format:

DayOfWeek Year-Month-Day Hour:Minute:Second

Where Year, Month, etc can be replaced either by a value, a comma seperated list, a range using .. and an asterisk *.

In order to start a timer you need to enabled and start it.

sudo systemctl enable $name.timer
sudo systemctl start $name.timer

Example

[Unit]
Description=Start the blackslist

[Timer]
OnCalendar=*-*-* 9:00:00

[Install]
WantedBy=timers.target