
How to Write systemd Unit Files: A Comprehensive Guide for Sysadmins
In the world of modern Linux systems, systemd is the undisputed standard for service management. It’s the first process that starts after the kernel boots and the last one to shut down, managing everything from simple scripts to complex daemons. To control how systemd handles your applications, you need to master its foundational component: the unit file.
A systemd unit file is a simple configuration file that declaratively describes a service, its dependencies, and how it should be executed. Forget complex shell scripting in init scripts; unit files provide a clean, powerful, and standardized way to manage system resources.
This guide will walk you through the anatomy of a systemd unit file, explaining the most important directives and providing a practical workflow for creating, managing, and securing your own services.
Understanding the Structure of a Unit File
At its core, a unit file uses a simple INI-style format, organized into sections denoted by square brackets (e.g., [Unit]). These files tell systemd what to do, not how to do it.
You’ll typically find unit files in two main locations:
- /usr/lib/systemd/system/: This is where unit files provided by installed software packages (via
aptoryum) are stored. You should not edit these files directly. - /etc/systemd/system/: This is where you, the system administrator, should place your custom unit files. Files in this directory take precedence over those in
/usr/lib/systemd/system/, allowing you to override default configurations safely.
The three most essential sections you will work with are [Unit], [Service], and [Install].
The [Unit] Section: Metadata and Dependencies
This section provides systemd with metadata about the unit and defines its relationship with other units on the system. It’s all about order and context.
Key directives include:
Description=: A straightforward, human-readable description of your service. This is what you’ll see in the output of commands likesystemctl status.After=: This is one of the most crucial directives for ordering. It specifies that your unit should only be started after the listed units are active. A common example isAfter=network.target, which ensures the network is up before your web application tries to start.Requires=: This defines a strong dependency. If your unit is started,systemdwill also start the units listed here. If one of the required units fails to start, your unit will also be deactivated.Wants=: A weaker version ofRequires=. Your unit will attempt to start the wanted units, but it will not fail if they are unable to start.
The [Service] Section: The Heart of Execution
This is the real workhorse section, defining how to start, stop, and manage the service process itself.
Essential directives are:
ExecStart=: This is the most important directive in the file. It specifies the full path and arguments of the command to be executed to start the service.Type=: Defines the startup behavior of the service. Common types include:simple(the default):systemdconsiders the service started as soon as theExecStartprocess is forked. This is ideal for modern applications that don’t daemonize themselves.forking: Used for traditional daemons that fork a child process and let the parent exit.systemdconsiders the service started once the parent process exits.oneshot: For scripts that perform a single task and then exit.
User=andGroup=: This is a critical security best practice. These directives specify the user and group under which the service process should run. Running services as a dedicated, non-privileged user significantly reduces the potential damage from a security vulnerability. Avoid running services asrootunless absolutely necessary.Restart=: Tellssystemdwhen to automatically restart the service. A very useful setting ison-failure, which will restart the service if it exits with a non-zero exit code.alwayswill restart it regardless of the exit code.ExecReload=: Specifies the command to execute to reload the service’s configuration without a full restart (e.g.,kill -HUP $MAINPID).WorkingDirectory=: Sets the working directory for the executed process.
The [Install] Section: Enabling Your Service
This section defines the behavior of the unit when it is “enabled” or “disabled” using the systemctl command. Enabling a service means it will start automatically at boot.
WantedBy=: This is the most common directive here. It specifies a target that should “want” this unit. A target is a synchronization point for grouping units. The most common value isWantedBy=multi-user.target, which hooks your service into the standard multi-user system startup process. When you runsystemctl enable myapp.service,systemdcreates a symbolic link in themulti-user.target.wantsdirectory, ensuring it starts on boot.
Putting It All Together: A Practical Example
Let’s create a unit file for a simple Python web application. Assume our app lives in /opt/myapp/ and is started with python3 /opt/myapp/app.py.
Create the file /etc/systemd/system/myapp.service:
[Unit]
Description=My Simple Python Web Application
# Start only after the network is available
After=network.target
[Service]
# Run the service as the 'webapp' user for security
User=webapp
Group=webapp
# Set the working directory for the application
WorkingDirectory=/opt/myapp
# The command to start the application
ExecStart=/usr/bin/python3 /opt/myapp/app.py
# Automatically restart the service if it fails
Restart=on-failure
[Install]
# Enable this service for the multi-user target
WantedBy=multi-user.target
Your systemd Workflow: A Step-by-Step Guide
Once you’ve created your .service file, follow these steps to manage it:
Reload the systemd Daemon: After creating or editing a unit file, you must tell
systemdto reread its configuration.sudo systemctl daemon-reloadStart Your Service: Manually start the service to test it.
sudo systemctl start myapp.serviceCheck the Status: Verify that your service is running correctly. This command is your best friend for debugging.
sudo systemctl status myapp.serviceThe output will show if it’s active, its main process ID (PID), and the latest log entries.
View Logs: For more detailed logs, use
journalctl.sudo journalctl -u myapp.serviceEnable the Service: If everything looks good, enable the service to start automatically on boot.
bash
sudo systemctl enable myapp.service
By understanding these fundamental building blocks, you gain precise control over your Linux services, making your systems more reliable, secure, and easier to manage.
Source: https://linuxhandbook.com/courses/systemd/create-systemd-units/


