Basics

systemd: What It Is, How It Works and How to Manage Services in Linux

Updated: · Skillaria.Top

systemd is the init system and service manager of Linux: the kernel starts it as the first process (PID 1), it brings up the other services in the right order and keeps watching them. Everything systemd manages is described by units — text descriptions of services, timers and mount points; systemctl starts, stops and enables them at boot, and journalctl shows their logs.

systemd is the init system and service manager used by most modern Linux distributions: Debian, Ubuntu, Fedora, RHEL and their derivatives. After boot the kernel starts systemd as the first process with PID 1, and from then on it brings up networking, mounts disks, starts the web server, the database and everything else. Put simply, systemd is the "dispatcher" that knows which services should be running, in what order to start them and what to do when a service fails.

To check that you have systemd, it is enough to run:

$ ps -p 1 -o comm=
systemd

Why systemd was introduced

Earlier, Linux used SysV init: a set of shell scripts in /etc/init.d/ that ran one after another. The scheme was understandable but slow and fragile. Each script wrote its own PID file, decided on its own how to check whether a process was alive, and restarting a crashed service had to be bolted on separately.

systemd solves these problems centrally:

  • Parallel start. Services start at the same time when there are no dependencies between them, so boot is faster.
  • Dependencies and order. The service description states explicitly what it needs (for example, the network) and what it should start after.
  • Supervision. systemd knows all processes of a service through cgroups and can restart it after a failure.
  • A single journal. The output of all services is collected by journald, and logs are read with one command.
  • A single interface. Every service is managed the same way: systemctl start|stop|restart|status.

Besides the service manager, the systemd project includes a set of components: journald (logging), logind (user sessions), timesyncd (time synchronization), resolved (DNS), networkd (networking). Not every distribution uses all of them, but systemd as PID 1 and journald are present almost everywhere.

Units: what systemd is made of

Everything systemd manages is described by units. A unit is a text file in INI format; its type is determined by the extension.

TypeExtensionWhat it describes
service.serviceA service — a daemon process or a one-off task
timer.timerRunning another unit on a schedule (a replacement for cron)
socket.socketA socket whose access starts a service
target.targetA group of units, a "system state" (for example multi-user.target)
mount.mountA mount point
path.pathWatching a file or directory

Where unit files live

Unit files are stored in several directories, and they have a priority order:

  • /usr/lib/systemd/system/ (on Debian and Ubuntu also /lib/systemd/system/) — units installed by packages. Do not edit them by hand: a package update will overwrite your changes.
  • /etc/systemd/system/ — the administrator's units and overrides. They have the highest priority.
  • /run/systemd/system/ — temporary units created while the system is running.

To see the effective content of a unit with all overrides, use systemctl cat nginx.service.

Targets instead of runlevels

Old runlevels have been replaced by targets. multi-user.target is the usual server mode without graphics, graphical.target is with a graphical desktop, and rescue.target is a single-user recovery mode. The current default target is shown by systemctl get-default and changed with systemctl set-default multi-user.target.

systemctl: managing services

systemctl is the main tool for working with systemd. Most commands change the system state and require sudo.

CommandWhat it does
systemctl status nginxService state, PID, memory, the last lines of the log
systemctl start nginxStart now
systemctl stop nginxStop
systemctl restart nginxRestart (stop + start)
systemctl reload nginxRe-read the configuration without stopping (if the service supports it)
systemctl enable nginxAdd to autostart
systemctl disable nginxRemove from autostart
systemctl enable --now nginxEnable autostart and start immediately
systemctl is-active nginxPrint active/inactive — handy in scripts
systemctl list-units --type=serviceLoaded services
systemctl --failedFailed units
systemctl daemon-reloadRe-read unit files after editing

How to read systemctl status

$ systemctl status nginx
● nginx.service - A high performance web server and a reverse proxy server
     Loaded: loaded (/lib/systemd/system/nginx.service; enabled; preset: enabled)
     Active: active (running) since Mon 2026-10-12 09:14:03 UTC; 2h 5min ago
       Docs: man:nginx(8)
   Main PID: 812 (nginx)
      Tasks: 3 (limit: 2307)
     Memory: 6.1M
        CPU: 154ms
     CGroup: /system.slice/nginx.service
             ├─812 "nginx: master process /usr/sbin/nginx -g daemon on; master_process on;"
             ├─813 "nginx: worker process"
             └─814 "nginx: worker process"

The Loaded line shows where the unit file comes from and whether autostart is enabled (enabled). The Active line is the current state: active (running), inactive (dead) or failed. The CGroup block lists all processes of the service — this is how systemd tracks what belongs to it.

enable versus start

This is a common confusion. start runs the service right now, but after a reboot it will not come up. enable creates a symbolic link in the target's directory (for example /etc/systemd/system/multi-user.target.wants/), so the service starts at boot, but it is not running now. You usually need both — use enable --now.

There is also a third state — mask. systemctl mask service links the unit to /dev/null, and it cannot be started either manually or as a dependency. It is useful when a service must be reliably turned off.

journalctl: service logs

Everything a service writes to stdout and stderr is captured by systemd-journald and stored in a binary journal together with metadata: unit name, PID, priority and time. The journal is read with the journalctl command.

journalctl -u nginx              # logs of one service
journalctl -u nginx -f           # follow in real time, like tail -f
journalctl -u nginx --since "1 hour ago"
journalctl -u nginx -n 50        # last 50 lines
journalctl -b                    # since the current boot
journalctl -b -1                 # the previous boot
journalctl -p err -b             # only errors and above
journalctl -k                    # kernel messages
journalctl --disk-usage          # how much space the journal takes

The -p flag filters by syslog priority: emerg, alert, crit, err, warning, notice, info, debug. The chosen level includes everything more severe than it.

The journal after a reboot

If the directory /var/log/journal does not exist and /etc/systemd/journald.conf has Storage=auto, the journal is kept only in memory (/run/log/journal) and disappears on reboot. To make it persistent, set Storage=persistent or create the directory and restart journald. The size is limited by the SystemMaxUse= parameter, and old entries can be cleaned with journalctl --vacuum-time=2weeks or --vacuum-size=500M.

journald often works together with rsyslog: the journal forwards messages to rsyslog, which writes classic text files to /var/log/ and can send logs to a central server.

Autostart for your own service: a unit file example

Suppose you have an application — a script or a binary — that must stay running, start at boot and restart when it crashes. Create the file /etc/systemd/system/myapp.service:

[Unit]
Description=My web application
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=myapp
Group=myapp
WorkingDirectory=/opt/myapp
EnvironmentFile=/etc/myapp/env
ExecStart=/opt/myapp/bin/server --port 8080
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

Let's go through the sections:

  • [Unit] — description and dependencies. After= sets only the order, Wants= is a soft dependency (pull in the unit, but do not fail if it did not start). A hard dependency is Requires=.
  • [Service] — how to run it. Type=simple means the process from ExecStart is the service itself and does not go to the background. User= runs it as an unprivileged user. Restart=on-failure restarts the service if it exited with an error, after RestartSec seconds.
  • [Install] — what enable does. WantedBy=multi-user.target means "start on a normal boot".

Apply it:

sudo useradd --system --no-create-home --shell /usr/sbin/nologin myapp
sudo systemctl daemon-reload
sudo systemctl enable --now myapp
systemctl status myapp
journalctl -u myapp -f

Common mistakes in unit files

  • A relative path in ExecStart. The path to the program must be absolute. systemd does not search commands in the user's PATH the way a shell does.
  • Forgetting daemon-reload. After editing a file, systemd keeps using the old version and warns about it in status.
  • The daemon goes to the background. If the program forks itself but Type=simple is set, systemd decides the service has exited. Either run the program in the foreground, or use Type=forking with PIDFile=.
  • Environment variables from the profile. The service does not see ~/.bashrc or /etc/profile. Variables are set with Environment= or EnvironmentFile=.

Overriding without editing the package unit

To change a package service's parameters without touching its file, use a drop-in:

sudo systemctl edit nginx

An editor opens, and the changes are saved to /etc/systemd/system/nginx.service.d/override.conf. For example, you can add a [Service] section with Restart=always there. After you close the editor, systemd re-reads the configuration by itself.

systemd timers instead of cron

A timer is a unit that runs a service of the same name on a schedule. Compared with cron: the task's logs go to the journal, dependencies are supported, and missed runs can be caught up (Persistent=true). Example — a nightly backup:

# /etc/systemd/system/backup.service
[Unit]
Description=Nightly backup

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh

# /etc/systemd/system/backup.timer
[Unit]
Description=Run backup daily

[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true

[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer
systemctl list-timers

You can check an OnCalendar expression with systemd-analyze calendar "*-*-* 03:00:00" — it shows when the next run will happen.

Diagnosing boot time

systemd records the start time of each unit, so slow boots are easy to analyze:

systemd-analyze                  # total boot time
systemd-analyze blame            # units sorted by start time
systemd-analyze critical-chain   # the chain that delayed the boot
systemd-analyze verify /etc/systemd/system/myapp.service   # check a unit file

Summary

systemd is PID 1 and the service manager of modern Linux. It describes everything with units, is controlled through systemctl, collects logs into a journal that is read with journalctl, and can run tasks with timers instead of cron. To use it confidently, master status, enable --now, journalctl -u, and be able to write a simple unit file with Restart=on-failure. systemd, journald and logging are covered in practice in our Linux course.

FAQ

How do I know whether my system uses systemd?

Run ps -p 1 -o comm= — if the output is systemd, the system runs under systemd. The directory /run/systemd/system also exists only when the system was booted with systemd.

What is the difference between systemctl restart and reload?

restart fully stops and starts the service again, and connections are dropped. reload asks the service to re-read its configuration without stopping, but it works only if the unit defines ExecReload.

Can systemd services run as an ordinary user without sudo?

Yes, systemd has a user instance: units go into ~/.config/systemd/user/ and are managed with systemctl --user. To keep them running without an active session, enable loginctl enable-linger for the user.

Why is a service in the failed state, and how do I reset it?

Look for the cause in journalctl -u name -b and in the Active line of status. After fixing the problem, start the service again; the failed mark is cleared with systemctl reset-failed.

Where are systemd logs stored on disk?

With persistent storage — in /var/log/journal/ in binary format; otherwise in /run/log/journal/ in memory. Read them with journalctl, not with text utilities.

Learn this topic on video

This topic is covered in depth with practice in the course “Linux: с нуля до уверенного администрирования”.

Go to course