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