EK Knowledge

Ubuntu/Debian

systemd Unit Files

A systemd unit file is a configuration file in an INI-like format. It defines how systemd manages a resource. A service file (.service), for example, specifies how a service is started, executed, and stopped.

1. File Locations

Depending on their origin and purpose, systemd unit files are stored in different directories.

  • /etc/systemd/system/ – for custom unit files and local overrides.
  • /usr/lib/systemd/system/ – for unit files provided by the operating system or installed packages. On older systems, this path may also be /lib/systemd/system/.

Custom service files should preferably be stored in /etc/systemd/system/.

2. Basic Structure

A typical service file looks like this:

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

[Service]
Type=simple
ExecStart=/usr/local/bin/my-own-service
Restart=on-failure

[Install]
WantedBy=multi-user.target

A unit file consists of sections whose names are enclosed in square brackets. Each configuration option belongs to a specific section.

Section Purpose
[Unit] General description, dependencies, and startup ordering
[Service] Service execution and supervision
[Install] Specifies how the service is integrated when enabled

Not every unit file requires all three sections. The permitted sections depend on the unit type.

3. Syntax of Entries

An entry normally consists of a key, an equals sign, and a value:

Key=Value

Examples:

Description=My Own Service
Restart=on-failure

The following rules apply:

  • Case sensitivity: Option names must use the prescribed spelling, for example, ExecStart=.
  • Blank lines: Can be used to improve readability.
  • Comments: Lines beginning with # or ; are comments.
  • Values: The handling of whitespace, quotation marks, and special characters depends on the specific option and the syntax rules.
  • Sections: An option belongs to the section in which it is defined. Section names are enclosed in square brackets.

Example with comments:

[Service]
# Command to start the service
ExecStart=/usr/local/bin/my-own-service

# Restart the service if it fails
Restart=on-failure

4. The [Unit] Section

This section contains general information about the unit, as well as its dependencies and startup ordering.

Option Description
Description= Description of the unit
After= Defines startup ordering relative to other units
Before= Specifies that this unit should be started before another unit
Requires= Defines a dependency on other units
Wants= Defines a weaker dependency on other units

Important: After=network.target does not guarantee that a network connection is available. The option only defines startup ordering. Dependencies and startup ordering are two different things.

5. The [Service] Section

This section specifies how the service is executed and supervised.

Option Description
Type= Defines how systemd determines whether the service has started
ExecStart= Command to execute when starting the service
ExecStartPre= Command executed before the service starts
ExecStartPost= Command executed after the service has started successfully
ExecStop= Command used to stop the service
Restart= Defines the conditions under which the service is restarted
User= User under which the service runs
WorkingDirectory= Working directory of the service
Environment= Sets environment variables
Common Values for Type=
  • simple – the service is considered started as soon as its process has been started.
  • exec – the service is considered started once the configured process has been successfully executed.
  • forking – for programs that fork into the background during startup.
  • oneshot – for tasks that execute and then terminate.
  • notify – for programs that explicitly notify systemd when they are ready.
  • idle – delays execution until other startup jobs have completed.

For many simple services, simple or exec is suitable. The appropriate choice depends on the program and the systemd version in use.

Common Values for Restart=
  • no – no automatic restart.
  • on-failure – restart when the service fails.
  • on-abnormal – restart after an abnormal termination, for example, due to an uncaught signal.
  • always – restart regardless of whether the process terminates successfully or with an error.

6. The [Install] Section

This section describes how a unit is integrated when enabled with systemctl enable.

Option Description
WantedBy= Defines the target whose dependency structure includes the unit when it is enabled
RequiredBy= Defines a target that acquires a stronger dependency on the unit when it is enabled
Alias= Defines additional names for the unit

A commonly used entry is:

[Install]
WantedBy=multi-user.target

This causes the service to be added to the startup dependencies of multi-user.target when it is enabled.

The [Install] section is not evaluated on every start. systemctl enable uses it to create the corresponding symbolic links.

7. ExecStart= Is Not a Shell

A common mistake is to assume that systemd automatically executes the contents of ExecStart= through a shell.

The following example does not automatically execute a shell pipeline:

ExecStart=/usr/bin/command1 | /usr/bin/command2

The pipe character | is not interpreted as a shell operator here. Redirections such as > and background execution using & do not work as they would in a shell either.

If a shell is required, it must be invoked explicitly:

ExecStart=/bin/sh -c 'command1 | command2'

In this case, the shell interprets the pipeline.

8. Validating Unit Files and Reloading Changes

Validate the Configuration

systemd-analyze verify can be used to check a unit file for syntax errors and other configuration problems:

systemd-analyze verify /etc/systemd/system/my-own-service.service
Reload Changes

After creating a new unit file or modifying an existing one, systemd must reload its configuration:

systemctl daemon-reload
Start the Service
systemctl start my-own-service
Display the Service Status
systemctl status my-own-service
Enable Automatic Startup
systemctl enable my-own-service
Start the Service and Enable Automatic Startup
systemctl enable --now my-own-service

9. Official Documentation