SystemD
The SystemD is a application startup manager designed in 2010. It
is an answer to the previous manager SysV, which has it’s downsides.
The main issue that was targeted to be fixed is long booting times
due to the sequentially executed programs. The order of the
application startups were controlled in etc/init.d
directory by manually manipulating the priorities.
This was tedious solution and hard to maintain in a longer time
span. The SystemD resolves the issue by creating a centralized tool
for maintaining dependencies and run levels - the
systemctl.
The new way of Linux startup has it’s fans and opponents due to the additional complexity it brings. Therfore on some distributions such Linux Alpine you will not found SystemD solution, instead they are shipping OpenRC which is flavored version of SysV. ## The “unit”
The most atomic structure is unit which describes the program that suppose to be run. The file can be stored in few places in the system:
/usr/lib/systemd/system/: units provided by installed packages/run/systemd/system/: units installed by the system administrator, (deleted on power-off )/etc/systemd/system/: units installed by the system administrator~/.config/systemd/user: units provided by the user
Creating the services file will be automatically visible by the
systemctl tool in the auto-completion list.
The unit file are following some standardized naming convention (but are not mandatory). The most important are listed below:
| Service unit | .service |
A system service. |
|---|---|---|
| Target unit | .target |
A group of systemd units. |
| Device unit | .device |
A device file recognized by the kernel. |
| Mount unit | .mount |
A file system mount point. |
| Swap unit | .swap |
A swap device or a swap file. |
| Timer unit | .timer |
A systemd timer. |
| System service | .service |
A system service |
More of the examples can be found on RedHat Docs1. Registered paths can be also displayed with:
systemd-analyze unit-pathsStructure of the unit
The unit file is a text based file which contains three main sections:
[Unit]- contains metadata about the unit, which describes dependencies, and conditions when the unit suppose to be launched.[Service]- describes how the process suppose to be executed.[Install]- This section is not interpreted by systemd during runtime; it is used by the enable and disable commands of the systemctl tool during installation of a unit2.
Example service created for custom program that overwrites the keyboard behavior:
[Unit]
Description=Thinkpad keyboard backlight service
[Service]
User=root
Group=root
ExecStart=/usr/bin/thinkpad-keybacklight
Type=exec
Restart=always
[Install]
WantedBy=default.target
The unit file has description of “Thinkpad keyboard backlight
service”, and is executing
/usr/bin/thinkpad-keybacklight. The program is suppose
to be run by the root and in case of any error the
program should be automatically restarted. The unit file must be run
on the defualt synchronization points - what is after
the text or graphical environment is loaded.
Targets
Targets are the synchronization points, it is alternative to the
run levels which were used in the SysV. By targeting the unit file
on a certain target we can loosely say after which booting stage our
program suppose to be launched. Targets allow to create dependency
tree much easier, what results in faster system booting times,
because not all programs are not strictly chained together. We can
try to imagine targets as a group of programs that must be run
together to achieve the synchronization point. In case we need some
dependency for certain unit within the group we can use dedicated
settings in the unit file like
WantedBy=sample.service.
You can check what kind of targets are defined in your system with:
systemctl list-units --type=targetThe most important are usually:
poweroff.target- When the device is power offrescue.target- The device is in rescue modemulti-user.target- Text mode with network interfaces running upgraphical.target- The graphical environment worksreboot.target- Reboot
When creating simple services we can use
default.target which is usually pointing at the
multi-user or graphical target. The
service will be reached when almost all other services are up and
running, so we can take advantage of those in our programs.
Unit file settings
There if a lot of other settings that might be useful when
creating own unit files. Everything is accessible in the
man systemd.services or on freedesktop3.
systemctl
The systemctl is the main application which allows
us to control the systemD environment. With the command we can
instruct which units should be enabled/disabled, restart them, check
logs, statuses etc.
To see the list of currently running services use:
systemctl listTo see details about the service use:
systemctl status <service>● thinkpad-keybacklight.service - Thinkpad keyboard backlight service
Loaded: loaded (/etc/systemd/system/thinkpad-keybacklight.service; enabled; preset: enabled)
Active: active (running) since Wed 2026-03-18 16:00:59 CET; 1 month 1 day ago
Main PID: 1355 (thinkpad-keybac)
Tasks: 1 (limit: 37887)
Memory: 712.0K (peak: 2.1M)
CPU: 15min 2.869s
CGroup: /system.slice/thinkpad-keybacklight.service
└─1355 /usr/bin/thinkpad-keybacklight
Mar 18 16:00:59 username systemd[1]: Starting thinkpad-keybacklight.service - Thinkpad keyboard backlight service...
Mar 18 16:00:59 username systemd[1]: Started thinkpad-keybacklight.service - Thinkpad keyboard backlight service.
The command will show not only the current status of the service, but also statistics regarding the CPU and memory consumption, and logs this program sent.
You will see the whole tree of services. Each slice means a cgroup, which has its own resource limits. This might be useful when we would like to create service that has limited accesses/resources. Also, you will be able to see what kind of other forks the process did.
When the new unit file is created first we need to enable it with:
systemctl enable <service>then when it is enabled we must start it manually, or restart the device:
systemctl start <service>The opposite actions are:
systemctl stop <service>
systemctl disable <service>.
Service stopped but not disabled will be restarted automatically after the device reboot. You can simply restart the unit by calling:
systemctl restart <service>Overwriting services
During the system update default services will be overwritten with new versions. In case you need to edit the default services you should use drop-in file, which will be preserved and used instead of the default one. You can use:
systemctl edit <service>
or do it manually by creating in the services folder,
subdirectory named
<service>.service.d/override.conf
Refreshing unit files
When experimenting and modifying unit-files sometimes the new changes might not be consumed by the systemd. In that case the systemd should be reloaded with:
systemctl reloadTimers
The systemD is suppose to be the alternative to the CRON for executing periodic tasks. The “timer” type of units gives ability to schedule execution of units based on two types of clocks:
- Monotonic clock - it is a timer that starts counting when the device is started,
- Calendar clock - it is a timer based on the calendar time.
Units of timer type have .timer extension.
The unit itself can execute the program directly after the time elapses, or can trigger other unit. Triggering other unit is cleaner approach as this gives clear distinction between program execution, and trigger type. Keep in mind that the official manual suggest keeping the names of unit files the same (despite of extension) for easier tracing 4.
Monotonic timer
Example timer for running backup shell script
[Unit]
Description=Hourly Backup Timer
Requires=backup.service
[Timer]
OnBootSec=5min
OnUnitActiveSec=1h
AccuracySec=1min
Persistent=true
[Install]
WantedBy=timers.target
This will create a timer with description “Hourly Backup
Timer”. That will run backup.service unit (notice
it is using Requires not Wants what create
much stronger dependency - the unit file cannot fail to end
successfully). The timer is scheduled to be run for the first time 5
min after the device bootup, and repeated every 1h from the last
activation. The Persistent forces the unit to be
triggered even if it the timer was not activated fro the first 5 min
from the start. This flag allow you to fix missed triggers. By
specifying the timers target be ensure we run the unit
after the timer is actually initialized in our system.
Calendar timer
You can adjust the timer schedule using options like
OnCalendar= for specific times (e.g.,
OnCalendar=daily or
OnCalendar=*-*-* 02:00:00 for 2 AM daily).
For the common patterns for e.g. to run every 1 min use:
man systemd.timeThe following special expressions may be used as shorthands for longer normalized forms:
- minutely → --* ::00
- hourly → --* *:00:00
- daily → --* 00:00:00
- monthly → --01 00:00:00
- weekly → Mon --* 00:00:00
- yearly → *-01-01 00:00:00
- quarterly → *-01,04,07,10-01 00:00:00
- semiannually → *-01,07-01 00:00:00
journalctl
For further debugging using logs we can take advantage of the
journalctl command to see all logs coming from our unit
test file:
journalctl -u <service>