Custom systemd service

Posted on Sun 10 October 2021 in linux

The management of services in latest Debian releases is managed by systemd. Systemd provides a flexible way to manage and configure system services. Also long running Python applications, such as network services, can easily be integrated as systemd service.

Before diving into a concrete example, first, the idea of .service files will be explained as well as the most important configuration options that can be used to setup the service will be discussed.

Service files

Each service is configured using a .service file that is located in the /etc/systemd/system directory. Systemd will then load these service files and start them depending on the set options.

For each service one of the following types must be chosen: simple, exec, forking, oneshot, dbus, notify or idle. Details about the service types can be found in the corresponding systemd manpage. For most cases the simple type can be used that is for long running services.

The most important configuration options for a service are:

General options

  • Description - name of the service
  • Type - simple, forking, oneshot, dbus, notify or idle; here simple is used that is suitable for long running process as considered here.

Environment options

  • WorkingDirectory - before the service will be executed it will be changed in this directory
  • User - the user that is used to start the service
  • Group - the group that is used to start the service
  • Environment - set environment variables

Execution

  • ExecStart - application that will be started
  • ExecStartPre - command that is started before the service
  • ExecStartPost - command that is started after the service

Restarting

  • Restart - restart option (always, on-success, on-failure, on-abnormal, on-watchdog or on-abort)
  • RestartSec - sleep time before restarting

Dependencies

  • After - service that must be started before own service
  • WantedBy - corresponds to earlier 'run levels', for multi-user systems simply multi-user.target can be used (earlier runlevel 3)

Example

In the following, an example of a complete myservice.service file is shown that includes the start of the Python script using its virtual environment:

[Unit]
Description=My Service
After=network.target

[Service]
Type=simple
WorkingDirectory=/home/user/script
Environment=SECRET_KEY=secret_password
ExecStart=/home/user/script/env/bin/python yourscript.py
User=myuser
Group=mygroup
Restart=always

[Install]
WantedBy=multi-user.target

The service will be started after the network is available. An environment variable is set that can be accessed by the Python script. The python script is started via a virtual environment. The Python script itself is located in the working directory. Also a specific user and group is used to isolate the service from other services.

Using the service

Before the new service file can be used, systemd needs to be notified to read all services files in again:

systemctl daemon-reload

In the next step, the service can be started:

systemctl start myservice.service

After the service was started, check its status using the following command:

systemctl status myservice.service

Further information could be easily obtained using the syslog, which is particularly helpful in the case of errors:

journalctl -u myservice.service

If your are sure that everything is running as expected, tell systemd to start the service each boot:

systemctl enable myservice.service

To disable the service again simply call:

systemctl disable myservice.service

Of course there are several more options that can be used to configure certain details of the service.