SystemD – What is SystemD used for?

SystemD Featured Image

systemd is the init system and service manager on nearly every major Linux distribution. It runs as process ID 1, starts services at boot, restarts them when they fail, and collects logs through journald. You control it with systemctl and read logs with journalctl. The current release is systemd 262.

Short version

Terminalbash
systemctl status nginx           # is the service running?
sudo systemctl enable --now nginx  # start now and at every boot
sudo systemctl restart nginx
systemctl cat nginx              # show the unit file
journalctl -u nginx -f           # follow the service log
systemd-analyze blame            # what slows down boot?

In this article, you will learn what systemd does, how unit files, targets and control groups work, and which commands you need day to day.

Table of Contents

What is SystemD used for?

systemd manages the processes on a Linux machine from boot to shutdown. It starts services in parallel, mounts filesystems, brings up devices and sockets, and keeps track of every process in a control group. It also ships tools for logging (journald), scheduled jobs (timers), hostnames, time and more.

Whether you run a large server or a laptop, the everyday tasks look the same:

  • start, stop, restart and enable services
  • restart crashed services automatically
  • read logs per service
  • limit CPU and memory per service
  • find out what makes boot slow

Why do people dislike SystemD?

Mostly because of its scope. systemd started as an init system and grew into a large suite that also handles logging, networking, DNS resolving, login sessions and more. Critics say this breaks the Unix idea of small tools that do one job. Others dislike that journald stores logs in a binary format, so you need journalctl instead of grep on a text file.

None of this makes it slow or insecure by itself. For most admins the unit-file syntax is simpler than the old init shell scripts.

Why is SystemD controversial?

Distributions adopted it between 2012 and 2015, and it replaced the init system that everyone knew. Because other components such as GNOME started to depend on it, some users felt they could not avoid it. A few distributions, for example Devuan, Alpine and Void, still ship other init systems.

What is SystemD vs init?

The classic System V init starts services one after another by running shell scripts in /etc/init.d. systemd describes services in declarative unit files, starts them in parallel based on dependencies, and tracks them with control groups. That is why boot is usually faster and why systemd can reliably stop every process of a service. systemd 260 removed support for the old SysV init scripts, so services need native unit files now.

Should I use Grub or SystemD?

You don’t have to choose, because they do different jobs. A bootloader such as GRUB loads the kernel. After that, the kernel starts systemd as the first process. If you want a simpler bootloader, systemd also ships systemd-boot for UEFI systems.

How to use SystemD

SystemD Top Image

Next, we will cover a couple of ways in which you can use systemd on Linux systems. These are just a few examples that you can try out yourself. It takes some time to get used to the syntax, but once you have it down, systemd is easy to work with.

SystemD - Init

This is the first process started by the kernel and gets the process id 1. It manages the boot process and tasks like creating sockets, setting up hardware, mounting disks, etc.

systemd works with units of different types. Next to the service itself, there also exist:

  • timer
  • mount
  • socket
  • path
  • device
  • target
  • slice

Furthermore, you can manage other processes with SystemD:

  • start
  • stop
  • restart
  • kill

Unit-Files

There are different paths for existing unit files:

Path Info
/usr/lib/systemd/system predefined SystemD files (do not modify)
/etc/systemd/system Location for custom unit files
/run/systemd/system For the runtime relevant files

Important information about the paths: SystemD will always prefer /etc/ to /usr/lib/. This is why we place custom unit files there.

You can visit the unit file of a specific service by visiting the path or with the command:

Terminalbash
systemctl cat <service>

For example, OpenVPN:

Terminalbash
root@max-desktop:~$ systemctl cat openvpn
# /lib/systemd/system/openvpn.service
# This service is actually a systemd target,
# but we are using a service since targets cannot be reloaded.

[Unit]
Description=OpenVPN service
After=network.target

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/true
WorkingDirectory=/etc/openvpn

[Install]
WantedBy=multi-user.target

As we can see, the unit file defines a description, the start order (After=), the command to run (ExecStart=) and the target that pulls it in at boot (WantedBy=). We can view all properties of the service, including the defaults that are not in the file, with:

Terminalbash
systemctl show <service>

For example, here again, are the first lines of the output of OpenVPN:

Terminalbash
root@max-desktop:~$ systemctl show openvpn
Type=oneshot
Restart=no
NotifyAccess=none
RestartUSec=100ms
TimeoutStartUSec=infinity
TimeoutStopUSec=1min 30s
TimeoutAbortUSec=1min 30s
TimeoutStartFailureMode=terminate
TimeoutStopFailureMode=terminate
RuntimeMaxUSec=infinity
WatchdogUSec=0
WatchdogTimestamp=n/a
WatchdogTimestampMonotonic=0
RootDirectoryStartOnly=no
RemainAfterExit=yes
GuessMainPID=yes
MainPID=0
ControlPID=0
FileDescriptorStoreMax=0
NFileDescriptorStore=0
StatusErrno=0
Result=success
ReloadResult=success
CleanResult=success
UID=[not set]
GID=[not set]
NRestarts=0
OOMPolicy=stop
ExecMainStartTimestamp=Sat 2022-09-17 13:00:55 CEST
ExecMainStartTimestampMonotonic=9823235
ExecMainExitTimestamp=Sat 2022-09-17 13:00:55 CEST
ExecMainExitTimestampMonotonic=9824084
ExecMainPID=1164
ExecMainCode=1
ExecMainStatus=0

If we want to change a unit, we should not edit the packaged file in /usr/lib/systemd/system. Instead, we run:

Terminalbash
sudo systemctl edit <service>

This opens an empty drop-in file at /etc/systemd/system/<service>.service.d/override.conf. Only the options you put there change, and package updates do not overwrite them. If you really want a full copy of the original file to edit, add the --full option.

As an example, let’s say we want a service to restart by itself when it crashes. We open the editor for the service and add:

iniini
[Service]
Restart=on-failure
RestartSec=5

systemctl edit reloads the configuration for us when you save. If you edit a unit file by hand, you need to reload the unit files yourself:

Terminalbash
sudo systemctl daemon-reload

And finally, restart the service:

Terminalbash
sudo systemctl restart <service>

With this command, systemd will try to reload the service’s own configuration. If the service does not support reloading, it will restart the service:

Terminalbash
sudo systemctl reload-or-restart <service>

In the above commands, we learned how to control services manually. SystemD also allows you to permanently enable or disable services so that they either start automatically when needed or are not available at all. The following table will show the available commands:

Command Function
enable Starts a service automatically at boot
disable Stops a service from starting automatically at boot
is-enabled Check if a service is enabled
reenable Disables a service and then enables it again
mask Completely blocks a service so nothing can start it, be careful
unmask Removes the mask from a service

Usage example:

Terminalbash
sudo systemctl enable --now <service>

The --now option starts the service right away as well.

Targets

Targets are the different states in which the system can boot.

systemd replaces the well-known run levels. The older principle is retained, only the run levels are given names instead of numbers:

Target Effect
halt.target Stops the system without powering it off
poweroff.target Physically shuts down the system (power off)
rescue.target Single-user mode
multi-user.target Multiuser mode
graphical.target Multiuser mode with graphical interface
reboot.target Reboots the system

You can switch to another target by using the following command:

Terminalbash
systemctl isolate example.target

Reboot the system:

Terminalbash
systemctl reboot

Puts the system into hybrid sleep, which saves the state to disk and suspends to RAM:

Terminalbash
systemctl hybrid-sleep

Powers off the system:

Terminalbash
systemctl poweroff

The classic shutdown command is still available and accepts a time and a message. This reboots the system immediately:

Terminalbash
sudo shutdown -r now

There are many different parameters to use this command. You can look them up on the man page.

You can display the current target the system is booting into with the following command:

Terminalbash
systemctl get-default

Additionally, you can change the default target:

Terminalbash
sudo systemctl set-default example.target

The different runlevels can also be viewed here:

Terminalbash
ls -la /usr/lib/systemd/system |grep runle*
Snippettext
root@max-desktop:~$ ls -la /usr/lib/systemd/system |grep runle*
lrwxrwxrwx  1 root root    15 Apr 18 22:12 runlevel0.target -> poweroff.target
lrwxrwxrwx  1 root root    13 Apr 18 22:12 runlevel1.target -> rescue.target
drwxr-xr-x  2 root root  4096 Jan 28  2022 runlevel1.target.wants
lrwxrwxrwx  1 root root    17 Apr 18 22:12 runlevel2.target -> multi-user.target
drwxr-xr-x  2 root root  4096 Jan 28  2022 runlevel2.target.wants
lrwxrwxrwx  1 root root    17 Apr 18 22:12 runlevel3.target -> multi-user.target
drwxr-xr-x  2 root root  4096 Jan 28  2022 runlevel3.target.wants
lrwxrwxrwx  1 root root    17 Apr 18 22:12 runlevel4.target -> multi-user.target
drwxr-xr-x  2 root root  4096 Jan 28  2022 runlevel4.target.wants
lrwxrwxrwx  1 root root    16 Apr 18 22:12 runlevel5.target -> graphical.target
drwxr-xr-x  2 root root  4096 Jan 28  2022 runlevel5.target.wants
lrwxrwxrwx  1 root root    13 Apr 18 22:12 runlevel6.target -> reboot.target
-rw-r--r--  1 root root   803 Apr 18 22:12 systemd-update-utmp-runlevel.service

Control-Groups

systemd organizes tasks in control groups (cgroups). This is used for resource control in Linux, and this allows available resources to be limited, prioritized, counted, and isolated.

The following commands are, therefore, very useful for analyzing and optimizing system performance:

Terminalbash
systemd-analyze

This command can be used to determine boot performance.

Snippettext
root@max-desktop:~$ systemd-analyze
Startup finished in 12.712s (firmware) + 328ms (loader) + 8.240s (kernel) + 6.634s (userspace) = 27.916s 
graphical.target reached after 6.631s in userspace

As we can see, we get a breakdown of the timings of how long each task takes to start.

With the additional command blame we get a very detailed list of how long which single process needs to start up:

Snippettext
systemd-analyze blame

Output:

Snippettext
root@max-desktop:~$ systemd-analyze blame
5.573s NetworkManager-wait-online.service
3.244s plymouth-quit-wait.service
2.285s fwupd.service
 467ms logrotate.service
 392ms lm-sensors.service
 385ms accounts-daemon.service
 362ms snapd.service
 290ms systemd-resolved.service
 279ms networkd-dispatcher.service
 247ms networking.service
 213ms dev-nvme0n1p3.device
 182ms apparmor.service
 178ms ModemManager.service
 174ms systemd-journal-flush.service
 168ms udisks2.service
 161ms NetworkManager.service
 152ms com.system76.Scheduler.service
 128ms apport.service
 127ms e2scrub_reap.service
 116ms rsyslog.service
 115ms smartmontools.service
 114ms wpa_supplicant.service
 105ms systemd-cryptsetup@cryptswap.service
 100ms gpu-manager.service
....

If we want to see all control groups, we can use:

Terminalbash
systemd-cgls

or

Terminalbash
systemctl status

We will get a tree-based output with all the necessary information:

Snippettext
root@max-desktop:~$ systemd-cgls
Control group /:
-.slice
├─user.slice 
│ └─user-1000.slice 
│   ├─user@1000.service 
│   │ ├─session.slice 
│   │ │ ├─dbus-broker.service 
│   │ │ │ ├─3119 /usr/bin/dbus-broker-launch --scope user
│   │ │ │ └─3120 dbus-broker --log 4 --controller 10 --machine-id 04d8535513777afc7bb291c362dd90a7 --max-bytes 100000000000000 --max-fds 25000000000000 --max-matches 50000000>
│   │ │ ├─xdg-document-portal.service 
│   │ │ │ ├─3761 /usr/libexec/xdg-document-portal
│   │ │ │ └─3773 fusermount3 -o rw,nosuid,nodev,fsname=portal,auto_unmount,subtype=portal -- /run/user/1000/doc
│   │ │ ├─xdg-desktop-portal.service 
│   │ │ │ └─3753 /usr/libexec/xdg-desktop-portal
│   │ │ ├─pipewire-pulse.service 
│   │ │ │ └─3112 /usr/bin/pipewire-pulse
│   │ │ ├─wireplumber.service 
│   │ │ │ └─3111 /usr/bin/wireplumber
│   │ │ ├─plasma-xdg-desktop-portal-kde.service 
│   │ │ │ └─3861 /usr/lib/x86_64-linux-gnu/libexec/xdg-desktop-portal-kde
│   │ │ └─pipewire.service 
│   │ │   └─3106 /usr/bin/pipewire
│   │ ├─background.slice 
│   │ │ ├─plasma-kactivitymanagerd.service 
│   │ │ │ └─3546 /usr/lib/x86_64-linux-gnu/libexec/kactivitymanagerd
│   │ │ ├─plasma-kscreen.service 
│   │ │ │ └─3610 /usr/lib/x86_64-linux-gnu/libexec/kf5/kscreen_backend_launcher
│   │ │ ├─plasma-baloorunner.service 
│   │ │ │ └─5633 /usr/lib/x86_64-linux-gnu/libexec/baloorunner
│   │ │ ├─plasma-kglobalaccel.service 
│   │ │ │ └─3452 /usr/bin/kglobalaccel5
│   │ │ └─tracker-miner-fs-3.service 
│   │ │   └─3148 /usr/libexec/tracker-miner-fs-3
│   │ ├─app.slice 
│   │ │ ├─app-\\x2fusr\\x2fbin\\x2fkorgac-d27ecb9065d646918a10df1c4fa798fe.scope 
│   │ │ │ └─3599 /usr/bin/korgac -session 10dfe2702d000165869202400000083140007_1663442587_18526
│   │ │ ├─gvfs-goa-volume-monitor.service 
│   │ │ │ └─3171 /usr/libexec/gvfs-goa-volume-monitor
│   │ │ ├─app-dbus\\x2d:1.2\\x2dorg.gnome.OnlineAccounts.slice 
│   │ │ │ └─dbus-:1.2-org.gnome.OnlineAccounts@0.service 
│   │ │ │   └─3174 /usr/libexec/goa-daemon
│   │ │ ├─xdg-permission-store.service 
│   │ │ │ └─3765 /usr/libexec/xdg-permission-store
│   │ │ ├─com.system76.SystemUpdater.Local.service 

With the systemd-cgtop command, we get a list of all control groups sorted by the current resource utilization:

Terminalbash
systemd-cgtop

Now, why is this important to us? Now we can analyze the resource utilization of individual processes and, if necessary, adjust the process’s priority or change the resource limit.

The man page gives us many possibilities to manage this:

Terminalbash
man systemd.resource-control

For example, if we want to set the memory limit of a specific service, we can use:

Terminalbash
sudo systemctl set-property example.service MemoryMax=1G

MemoryLimit= is deprecated and only works on the old cgroup v1 hierarchy, so use MemoryMax=.

Logging - JournalD

journald collects the logs of the kernel, of services and of the boot process in one place. Whether they survive a reboot depends on the Storage= setting in /etc/systemd/journald.conf. With the default auto, logs are kept on disk if the directory /var/log/journal exists and only in RAM otherwise. Ubuntu and most other distributions create that directory, so their logs persist.

You can use JournalD with the following command:

Terminalbash
journalctl

We can further refine the output by adding filters, for example, with a specific time:

Terminalbash
journalctl --since yesterday

We can refine it even more by specifying an exact time period from to:

Terminalbash
journalctl --since "2026-11-01 08:00" --until "2026-11-02 18:00"

Another way to filter is to follow specific services:

Terminalbash
journalctl -u example

We can also follow a specific service and filter just for this one:

Terminalbash
journalctl -fu example

We could also filter just for kernel events:

Terminalbash
journalctl -k

Or only the messages of the current boot, or only errors:

Terminalbash
journalctl -b
journalctl -p err

Journal logs can grow large. This trims them to 500 MB:

Terminalbash
sudo journalctl --vacuum-size=500M

FAQ

How do I check if a service is running with systemd?

Run systemctl status <service>. It shows whether the service is active, its main process ID and the last log lines. For scripts, systemctl is-active <service> prints just active or inactive.

How do I make a service start at boot?

Run sudo systemctl enable <service>, or sudo systemctl enable --now <service> to also start it immediately. systemctl is-enabled <service> tells you the current state.

How do I check if my system uses systemd?

Run ps -p 1 -o comm=. If it prints systemd, you are on systemd. Distributions such as Ubuntu, Debian, Fedora, Arch and RHEL use it by default.

What is the difference between systemd and systemctl?

systemd is the system and service manager that runs as process ID 1. systemctl is the command line tool you use to talk to it, for example to start, stop or enable services.

How do I create my own systemd service?

Create a file such as /etc/systemd/system/myapp.service with a [Unit], a [Service] section containing ExecStart=/path/to/your/program, and an [Install] section with WantedBy=multi-user.target. Then run sudo systemctl daemon-reload and sudo systemctl enable --now myapp.

Summary

systemd is the standard successor to the classic System V init daemon and gives the admin a lot of useful information and tools that speed up everyday work. If you want to learn more about other in-depth Linux topics, make sure to visit Max Wilke’s blog.

  • systemd is the init system and service manager on most Linux distributions. It starts services in parallel and runs as process ID 1.
  • Unit files describe services, timers, mounts and more. Put your changes in /etc/systemd/system.
  • Control groups let you limit and measure resources per service, and journald collects the logs.
  • Some admins dislike systemd for its large scope and binary logs, but it is the default on nearly every major distribution.

🐧 There are some related articles!
👉 Top Things to do after installing Kali Linux 👉 Linux on Windows - The Complete WSL 2 Tutorial Series 👉 Create Generalized Windows Images with FOG Server 👉 Install FOG Server on Ubuntu 👉 Install Kali Linux on Windows - Complete Guide 👉 The Complete Kali Linux and Windows Dual Booting Guide 👉 Cronjob - The Complete Guide to Cronjobs 👉 Open Bitlocker Drive on Linux - Quick & Easy

whoami

Max Wilke

Max works as an IT-Engineer in the intralogistics industry. For more than 6 years now, he is an it professional on the command line in Linux. In addition to his contributions as a guest author on Ceos3c, he regularly writes on his own blog.