systemd: What It Is, How It Works and How to Manage Services in Linux
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.
| Type | Extension | What it describes |
|---|---|---|
| service | .service | A service — a daemon process or a one-off task |
| timer | .timer | Running another unit on a schedule (a replacement for cron) |
| socket | .socket | A socket whose access starts a service |
| target | .target | A group of units, a "system state" (for example multi-user.target) |
| mount | .mount | A mount point |
| path | .path | Watching 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.
| Command | What it does |
|---|---|
systemctl status nginx | Service state, PID, memory, the last lines of the log |
systemctl start nginx | Start now |
systemctl stop nginx | Stop |
systemctl restart nginx | Restart (stop + start) |
systemctl reload nginx | Re-read the configuration without stopping (if the service supports it) |
systemctl enable nginx | Add to autostart |
systemctl disable nginx | Remove from autostart |
systemctl enable --now nginx | Enable autostart and start immediately |
systemctl is-active nginx | Print active/inactive — handy in scripts |
systemctl list-units --type=service | Loaded services |
systemctl --failed | Failed units |
systemctl daemon-reload | Re-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 isRequires=. - [Service] — how to run it.
Type=simplemeans the process fromExecStartis the service itself and does not go to the background.User=runs it as an unprivileged user.Restart=on-failurerestarts the service if it exited with an error, afterRestartSecseconds. - [Install] — what
enabledoes.WantedBy=multi-user.targetmeans "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
PATHthe 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=simpleis set, systemd decides the service has exited. Either run the program in the foreground, or useType=forkingwithPIDFile=. - Environment variables from the profile. The service does not see
~/.bashrcor/etc/profile. Variables are set withEnvironment=orEnvironmentFile=.
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.
This topic is covered in depth with practice in the course “Linux: с нуля до уверенного администрирования”.
- systemd: как на самом деле запускаются сервисы в современном Linux
- Журналы и мониторинг: journald, rsyslog и sysstat