Linux concept: systemd
Press the power button on almost any modern Linux machine and, once the kernel has loaded, a single program takes over and brings the whole system to life. It mounts your disks, starts your network, launches your SSH server and your database, and keeps them all supervised until you shut down. That program is systemd. It is the first thing the kernel runs, it never stops while the machine is on, and it is the manager every service on the system answers to. Understanding systemd is understanding how a Linux machine actually lives.
1. The Basics
The job of systemd is to be the system and service manager for Linux. When your machine boots, the kernel starts exactly one program directly, and gives it process ID 1 (PID 1). On nearly every mainstream distribution that program is systemd. Everything else you can see running, from a web server to a background timer to the mounting of a disk, is a child that systemd started, tracks, and can stop again.
Because it is PID 1, systemd is special. It is the ancestor of every other process, it never exits while the system runs, and if it were to crash the kernel would panic. So systemd has to be careful, small in its core, and reliable. It does its job by reading a set of description files called units and acting on them.
The key idea is the unit. Systemd does not think in terms of "programs" or "scripts". It thinks in units: small declarative files that describe something it should manage and how. The most common kind is the service, but there are units for mount points, timers, sockets, network devices, and whole system states. Every unit has a name ending in a type suffix, such as ssh.service or graphical.target.
The right mental model: systemd is the one manager that runs the entire machine, from the first second of boot to shutdown, and every manageable thing on the system, a service, a mount, a timer, a target, is described to it as a unit.
You do not usually talk to systemd directly. You use its family of command-line tools, above all systemctl to control units and journalctl to read logs. This article is about the manager itself: what it is, how it boots your machine, how units and targets fit together, how it tracks processes with control groups, and the surprising amount of a modern Linux system that is really systemd wearing different hats. It is verified against systemd version 255.
1.1 Seeing That systemd Is PID 1
You can confirm systemd is in charge with one command. Process 1 is the manager, and the boot program /sbin/init is just a link to it:
$ ps -p 1 -o comm=
systemd
$ ls -l /sbin/init
/sbin/init → /lib/systemd/systemd
For decades /sbin/init was the real first program. Today it points at systemd, which keeps old habits and boot loaders working while systemd does the actual job.
1.2 The First Look: What Is Running
To see what systemd is managing right now, ask it to list its units. Reading state needs no special rights:
$ systemctl # every unit currently loaded
$ systemctl status # a tree of the whole system
$ systemctl list-units --type=service --state=running
The output shows each unit, whether systemd loaded it correctly, and whether it is active. That single view, everything on the machine in one list, is the practical payoff of having one manager instead of a pile of separate scripts.
1.3 The Main Unit Types
Because "unit" is the one idea that ties systemd together, it helps to see the common types at a glance. The suffix on a unit's name tells you what kind it is, and the same verbs (start, stop, enable, status) work on all of them:
| Suffix | Unit type | Manages |
|---|---|---|
.service |
Service | A daemon or program, the most common unit |
.socket |
Socket | A port or socket that starts a service on first use |
.timer |
Timer | A scheduled job, a modern replacement for cron |
.mount |
Mount | A filesystem mount point |
.automount |
Automount | A mount point that mounts on first access |
.path |
Path | Watches a file or directory and starts a unit on change |
.target |
Target | A group of units and a whole system state |
.slice |
Slice | A branch of the resource-control (cgroup) tree |
.scope |
Scope | A group of processes systemd did not start itself |
.device |
Device | A hardware device systemd knows about |
Most days you touch only .service and .target units, but the rest use the exact same tools, which is a large part of systemd's appeal.
2. Where the Name Comes From
The name is two parts joined together: system plus d.
systemd = SYSTEM + d (for daemon)
A daemon is the classic Unix word for a program that runs quietly in the background rather than in front of a user. By long tradition such programs get a name ending in the letter d: the SSH server is sshd, the web server is httpd, the cron scheduler is crond. So systemd reads as "the system daemon", the background program that manages the system itself.
The authors write it lower-case, always as systemd, never "System D" or "SystemD". That is a deliberate style choice, matching the Unix daemons it takes charge of.
Once systemd existed, a whole family of tools grew up around it, and they share a naming pattern. Command tools that control one part of the system end in ctl; background helpers that systemd runs keep the systemd- prefix and the d ending:
| Name | Role |
|---|---|
systemd |
The manager itself, running as PID 1 |
systemctl |
The tool you use to control units |
journalctl |
The tool you use to read the log journal |
systemd-journald |
The daemon that collects all logs |
systemd-logind |
The daemon that tracks user logins |
systemd-networkd |
The daemon that can manage the network |
The pattern is worth learning, because when you meet a new systemd-something you can guess at once that it is a background helper, and a new somethingctl is the command you drive it with.
3. A Short History
To understand systemd you have to know what it replaced, because it changed how Linux starts up more than any other single project in the last twenty years.
For most of Unix history, the first program the kernel started was init, and the traditional design was SysV init, named after AT&T's UNIX System V. It was a set of shell scripts under /etc/init.d, run in a fixed order by numbered "runlevels". It worked, but it was slow, because it started services strictly one after another, and fragile, because each service was a hand-written script that had to track its own process. Booting a big server could take minutes.
Attempts to modernise init came first. Ubuntu shipped Upstart in 2006, an event-based system that reacted to things happening rather than a fixed script order. It was a real improvement, but it kept the script-heavy style.
systemd, first released in 2010 by Lennart Poettering and Kay Sievers at Red Hat, set out to replace init entirely with a new design. Its big ideas were:
- Describe services as small declarative unit files instead of shell scripts, so the manager, not each script, does the heavy lifting.
- Start independent services in parallel, using dependencies to work out the order, for a much faster boot.
- Track every service's processes reliably with kernel control groups (cgroups), so a service and all its children can always be found and stopped.
- Collect all logs into one structured journal instead of scattered text files.
| Era | Milestone |
|---|---|
| 1983 | UNIX System V sets the init-and-runlevels pattern that Linux later copies |
| 2006 | Ubuntu ships Upstart, an early event-based replacement for init |
| 2010 | systemd is released, using declarative units, parallel startup, and cgroups |
| 2014-2015 | Debian, Ubuntu, Fedora, RHEL, Arch, and SUSE adopt systemd as default |
| Today | systemd is the standard init on nearly all mainstream Linux distributions |
The move was not without argument. systemd is large and does much more than the old init, taking on jobs such as logging, network setup, and device management that used to belong to separate programs. Some administrators dislike this reach, and a few distributions (such as Devuan, a systemd-free fork of Debian) deliberately avoid it. But on a default modern install, systemd is what boots and runs your machine, and learning it is no longer optional.
Back to top4. Simple Use Cases
You meet systemd mostly through systemctl. A handful of everyday actions cover almost all early contact with it, and none of them requires you to write a file.
4.1 Check Whether Something Is Running
The command you will run most is status. It asks systemd about one unit and shows whether it is active, whether it starts at boot, its main process, and the last few log lines, all at once:
$ systemctl status ssh
● ssh.service - OpenBSD Secure Shell server
Loaded: loaded (/lib/systemd/system/ssh.service; enabled)
Active: active (running) since Sun 2026-07-12 09:14:02 CEST; 2h ago
Main PID: 812 (sshd)
CGroup: /system.slice/ssh.service
└─812 sshd: /usr/sbin/sshd -D [listener]
Two words matter most. active (running) means it is up now. The word enabled in the Loaded: line means it will also start at the next boot. Those are two separate facts, and telling them apart is the single most useful thing to learn about running services.
4.2 Start, Stop, and Enable
Changing a service's state needs administrator rights, so these commands take sudo:
$ sudo systemctl start nginx # run it now
$ sudo systemctl stop nginx # shut it down now
$ sudo systemctl restart nginx # stop then start, to apply new config
$ sudo systemctl enable --now nginx # start now AND at every boot
The --now flag is the bridge between "run it this second" and "run it after every reboot". Its full story, and the important gap between start and enable, belongs to the systemctl article; here it is enough to know systemd is the thing carrying out each request.
4.3 Ask How the Boot Went
Because systemd runs the whole boot, it can tell you exactly how long that boot took and what slowed it down. The tool is systemd-analyze:
$ systemd-analyze # total boot time, split by phase
Startup finished in 3.1s (kernel) + 8.4s (userspace) = 11.6s
$ systemd-analyze blame # slowest units, worst first
$ systemd-analyze critical-chain # the ordered chain that gated boot
No other init could answer these questions so directly. It is a good first sign that systemd knows, in detail, everything it started and when.
Back to top5. Moderate Use Cases
Once the basics feel routine, the next step is to describe your own work to systemd. This is where units stop being something the distribution ships and start being something you write.
5.1 Anatomy of a Unit File
A unit file is a plain text file in "INI" style: named sections in square brackets, each holding Key=Value lines. A service unit uses three sections, and each has a clear job:
[Unit]
Description=My Application
After=network.target
[Service]
ExecStart=/opt/myapp/app.sh
Restart=on-failure
User=myapp
[Install]
WantedBy=multi-user.target
| Section | Answers |
|---|---|
[Unit] |
What is it, and when should it start relative to other units |
[Service] |
What to run (ExecStart), as which user, and how to restart it |
[Install] |
Which target pulls it in when you enable the unit |
You save this as /etc/systemd/system/myapp.service, tell systemd to re-read its files, then enable it:
$ sudo systemctl daemon-reload # systemd notices the new file
$ sudo systemctl enable --now myapp # start it now and at every boot
The Restart=on-failure line is one of the strongest reasons to prefer a real unit over a hand-run script: if your program crashes, systemd brings it back automatically.
5.2 Targets: Grouping Units into System States
A target is a special unit that does not run a program. Instead it groups other units and stands for a whole system state. Targets are systemd's replacement for the old numbered runlevels:
| Target | Old runlevel | Meaning |
|---|---|---|
multi-user.target |
3 | Full system with networking, no graphical login |
graphical.target |
5 | Everything in multi-user, plus a desktop |
rescue.target |
1 | Single-user rescue shell, minimal services |
emergency.target |
- | Barest shell, almost nothing started |
The system boots into whatever default.target points to. You can read it, change it, or switch the running machine into another state:
$ systemctl get-default # e.g. graphical.target
$ sudo systemctl set-default multi-user.target # boot without a desktop
$ sudo systemctl isolate rescue.target # switch to rescue mode now
5.3 Timers: A Modern Replacement for cron
For decades, scheduled jobs meant cron. systemd offers its own scheduler in the form of timer units. A timer is a small unit that says when, paired with a service that says what. The pair looks like this:
# backup.timer
[Unit]
Description=Nightly backup
[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true
[Install]
WantedBy=timers.target
The matching backup.service holds the ExecStart= that does the work. Timers have real advantages over cron: they log to the journal like any service, they can catch up a missed run with Persistent=true, and you can list them all with one command:
$ systemctl list-timers # every timer, next and last run time
Back to top6. Advanced Use Cases
The features in this section are where systemd goes well beyond "start my program". They are the reason the project grew so large, and each one solves a problem the old init could not.
6.1 Socket Activation: Start on First Use
A socket unit lets systemd open a network port or local socket on a service's behalf, before the service itself is running. When the first connection arrives, systemd starts the real service and hands the connection over. The service can stay stopped until something actually needs it, saving memory:
$ systemctl status ssh.socket # the listener, even if sshd is idle
Socket activation also removes a whole class of boot-order bugs: a client can connect the moment systemd is up, because the socket exists immediately, and the connection simply waits while the service starts. It is the same idea that once made the classic inetd useful, built into the manager.
6.2 Resource Control With Control Groups
Every service systemd starts is placed in its own control group (cgroup), a kernel feature that groups processes and can measure and cap what they use. Because a service and all the processes it spawns live in one cgroup, systemd can always account for them together and, crucially, stop every last one of them. You set limits with plain directives in the [Service] section:
| Directive | Effect |
|---|---|
MemoryMax=512M |
Hard memory ceiling; the service is killed if it goes over |
CPUQuota=50% |
Never use more than half of one CPU core |
TasksMax=100 |
Cap the number of processes and threads |
IOWeight=10 |
Lower this service's share of disk bandwidth |
You can watch live usage as a tree that mirrors the cgroup layout:
$ systemctl status nginx # shows the service's cgroup and memory
$ systemd-cgls # the full control-group tree
$ systemd-cgtop # live per-service CPU, memory, and I/O
6.3 Sandboxing: Locking a Service Down
The [Service] section can also confine a service, shrinking what a compromised program could reach, with no container needed. These are among systemd's most underused settings:
| Directive | Effect |
|---|---|
ProtectSystem=strict |
Mount the whole filesystem read-only for the service |
ProtectHome=true |
Hide /home and /root from the service |
PrivateTmp=true |
Give the service its own private /tmp |
NoNewPrivileges=true |
Stop the service ever gaining more privileges |
A built-in scanner scores how exposed each service is and suggests what to add:
$ systemd-analyze security nginx # exposure score and per-setting advice
6.4 The Journal: One Log for Everything
systemd runs a logging daemon, systemd-journald, that captures the output of every unit, the kernel's messages, and its own events into one structured store. Nothing extra is needed for a service to be logged: whatever it prints is caught automatically. You read it with journalctl:
$ journalctl -u nginx # all logs for one unit
$ journalctl -b # everything since the last boot
$ journalctl -f # follow new messages live
Because the journal is structured, you can filter by unit, by time, by priority, or by boot, in ways scattered text files in /var/log never allowed. The journalctl article covers this in depth.
6.5 Your Own Personal systemd
Alongside the system manager running as PID 1, systemd starts a second, separate instance for each logged-in user: the user manager. It manages services that belong to you and need no root, such as a desktop component or a personal backup timer. You reach it by adding --user to any command:
$ systemctl --user status # your own units, no sudo
$ systemctl --user enable --now myapp
$ systemctl --user list-timers
User units live under ~/.config/systemd/user/. This explains a common surprise: a service you started with --user does not appear in a plain systemctl status, because that asks the system manager, not yours. To keep a user service running after you log out, enable lingering with loginctl enable-linger.
6.6 Transient Units: Managed Runs Without a File
Sometimes you want systemd to supervise a one-off command without writing a unit file at all. systemd-run creates a transient unit on the spot: systemd runs the command in its own cgroup, logs it to the journal, and forgets it when it ends. It is the quick way to borrow systemd's features for a single job:
$ sudo systemd-run --unit=backup-now /opt/backup.sh # run it now as a managed service
$ sudo systemd-run --on-active=10min /opt/backup.sh # run it once, 10 minutes from now
$ sudo systemd-run -p MemoryMax=200M ./import.sh # run it under a memory cap
This is ideal for a heavy task you want capped and logged, or a delayed one-shot without a permanent timer. Because the unit is transient, it leaves nothing behind on disk; while it runs you can watch it with systemctl status backup-now like any other service.
7. Something Most Users Do Not Know
7.1 systemd Is Not One Program, It Is a Whole Fleet
People say "systemd" as if it were a single binary, but it is a large collection of programs that work together. The manager at PID 1 is only the core; around it sit dozens of specialised daemons and tools. A quick look under /lib/systemd/ shows the scale:
$ ls /lib/systemd/systemd-*
systemd-journald systemd-logind systemd-udevd
systemd-networkd systemd-resolved systemd-timesyncd
systemd-oomd systemd-homed ... (dozens more)
Each takes on a job that used to belong to a separate, independent project:
| Component | Replaces the old |
|---|---|
systemd-journald |
syslog text-file logging |
systemd-logind |
ConsoleKit session tracking |
systemd-networkd |
ifupdown / network scripts |
systemd-resolved |
hand-edited DNS resolver setup |
systemd-timesyncd |
a full NTP daemon for simple clock sync |
systemd-udevd |
the standalone udev device manager |
This is exactly what its critics mean by "systemd does too much" and its fans mean by "it is finally consistent". Either way, it explains why the project feels so big: it is not one tool, it is a coordinated suite that took over many jobs at once.
7.2 Where systemd Sits in the Whole Boot
systemd does not start the machine from nothing; it takes over partway through a longer chain. Knowing the full sequence tells you which part is systemd's job and which happens before it even loads:
1. Firmware (UEFI or BIOS) powers up and finds a boot device
2. Bootloader (GRUB) loads the kernel and initramfs
3. Linux kernel starts and detects hardware
4. initramfs tiny temporary root, mounts the real disk
5. systemd (PID 1) takes over as the first real process
6. Targets reached services started up to the default target
7. Login prompt or desktop the system is ready
Everything up to step 4 happens before systemd exists, so a failure there, such as a missing kernel or a broken bootloader, is not something systemd can report. From step 5 on, the machine is systemd's responsibility, and it works upward through a chain of targets, each one a milestone:
local-fs.target → filesystems mounted
↓
sysinit.target → early one-time setup done
↓
basic.target → sockets, timers, and paths ready
↓
multi-user.target → all normal services running
↓
graphical.target → desktop login on top
Each target says it must come After= the previous one and Wants= the services in its group. Systemd starts everything it safely can in parallel within each stage, which is why a systemd boot is so much faster than the strict one-at-a-time order of SysV init. You can see the exact chain that gated your own boot with systemd-analyze critical-chain.
7.3 "Enabling" a Service Is Just a Symbolic Link
The word enable sounds like it flips a hidden switch. It does something far simpler: it creates a symbolic link. A unit's [Install] section names the target that wants it, such as WantedBy=multi-user.target. Enabling the unit makes a symlink to it inside that target's .wants directory:
$ sudo systemctl enable nginx
Created symlink /etc/systemd/system/multi-user.target.wants/nginx.service
→ /lib/systemd/system/nginx.service.
At boot, systemd reaches multi-user.target, sees the symlinks in its .wants directory, and starts each linked unit. That is the entire mechanism. Disabling just deletes the link, and masking a service links its name to /dev/null so nothing can start it. Once you know this, enabling stops being magic and becomes files you can list with ls.
7.4 systemd Talks to You Over D-Bus
When you run systemctl restart nginx, the systemctl program does not touch nginx at all. It sends a message to systemd (PID 1) over D-Bus, the standard message bus Linux programs use to talk to each other. systemd receives the request, checks whether you are allowed to make it, does the work, and records the result. This design explains several things:
- A polkit password dialog can appear on a desktop, because D-Bus lets systemd ask an authorization service whether to permit the action.
- Any program can manage services by speaking the same bus, not only
systemctl; you can watch that traffic withbusctl. systemctlis a thin client. The intelligence lives in the manager it talks to, not in the command.
7.5 It Tracks Processes by cgroup, So Nothing Escapes
Old init systems tracked a service by its PID file, and a program that forked cleverly could slip loose and keep running as an orphan. systemd closes that gap: because every service lives in its own cgroup, a stray child stays inside the same group no matter how it forks. When systemd stops the service, it stops the whole cgroup, so there are no leftover processes. This is why a modern systemctl stop is so much more reliable than the old "kill the PID and hope" approach, and it is the same accounting that lets systemd report a service's exact memory use.
7.6 You Can Boot Straight Into a Shell
Because targets are just system states, you can ask systemd for a minimal one at boot time by editing the kernel command line. Adding systemd.unit=rescue.target boots to a single-user rescue shell; emergency.target gives you the barest shell of all, useful when a broken /etc/fstab stops a normal boot. This is the systemd equivalent of the old trick of appending single or a runlevel number, and it turns "the machine will not boot" into a problem you can often fix from the same console.
8. Best Practices
- Let systemd manage your programs. A short
[Unit]/[Service]/[Install]file withRestart=on-failurebeats a hand-run script or anrc.localline: it starts at boot, restarts on crash, and logs automatically. - Never edit vendor unit files under
/lib/systemd/system. A package update overwrites them. Add a drop-in withsystemctl editinstead, so your changes survive. - Run
daemon-reloadafter any unit change. systemd caches unit files in memory; until you reload it keeps using the old version and your edits appear to do nothing. - Prefer timers over cron for new jobs. Timer units log to the journal, can catch up missed runs with
Persistent=true, and show their schedule withsystemctl list-timers. - Sandbox internet-facing services. A few lines such as
ProtectSystem=strict,PrivateTmp=true, andNoNewPrivileges=trueturn many full-system compromises into contained ones. Check the result withsystemd-analyze security. - Set resource limits on hungry services.
MemoryMax=andTasksMax=stop one runaway process from taking the whole machine down. - Use
systemd-analyzeto understand your boot.blameandcritical-chainshow what is slow and why, instead of guessing. - Read the manual. systemd is thoroughly documented;
man systemd,man systemd.unit, andman systemd.serviceare the reference.
$ man systemd # the manager and its concepts
$ man systemd.unit # options common to all units
$ man systemd.service # how to write a service unit
$ man systemd.timer # how to write a timer
Back to top9. Common Mistakes
9.1 Myth versus Reality
| Myth | Reality |
|---|---|
| "systemd is a single program." | It is a suite. The PID 1 manager is the core, but journald, logind, networkd, udevd, and many more are all part of it. |
| "systemd and systemctl are the same thing." | systemd is the manager that runs; systemctl is only the command you use to talk to it. |
| "Editing a unit takes effect right away." | systemd caches unit files. You must run daemon-reload, then restart the service, before a change applies. |
| "A target is like a program that runs." | A target runs nothing itself. It is a named group of units and a system state, the replacement for runlevels. |
| "Disabling a service guarantees it can never run." | A disabled unit can still be started by hand or pulled in as a dependency. Use mask for an absolute block. |
9.2 Other Traps to Avoid
- Forgetting
daemon-reloadafter editing a unit. This is the number-one cause of "my change did nothing". systemd is still using the cached copy. - Editing files in
/lib/systemd/system. The next package update silently overwrites them. Keep your changes in/etc/systemd/systemor a drop-in. - Looking for a user service in the system view. A unit started with
--userwill not show under a plainsystemctl status. Add--userto see it. - Confusing the unit name with the process name. The unit may be
ssh.servicewhile the running program issshd. Use tab completion orsystemctl list-unitsto find the exact unit. - Assuming logs live in
/var/log/*.log. On a default systemd system the record is the journal; read it withjournalctl, not by opening text files. - Ordering without requiring, or the reverse.
After=sets order but not dependency;Requires=sets dependency but not order. Real dependencies usually need both.
10. Summary
systemd is the program that boots and runs a modern Linux machine. It is the first process the kernel starts, it manages everything else as a unit, and it stays in charge until shutdown. Learn how it thinks, in units, targets, and control groups, and the whole system becomes something you can reason about instead of a mystery that "just boots".
- systemd is the system and service manager, running as PID 1, the ancestor of every other process on the machine.
- The name means "system daemon"; it heads a family of tools like
systemctlandjournalctland helpers likesystemd-journald. - It replaced SysV init's slow, script-based, one-at-a-time boot with declarative unit files, parallel startup, and cgroup tracking, arriving in 2010.
- Everything it manages is a unit: services, sockets, timers, mounts, and targets that group units into system states (the replacement for runlevels).
- You drive it with
systemctlto control units andjournalctlto read the one unified journal. - You can write your own
[Unit]/[Service]/[Install]file, schedule jobs with timer units instead of cron, and start services on demand with socket activation. - It can cap resources (
MemoryMax=,CPUQuota=) and sandbox services (ProtectSystem=,PrivateTmp=,NoNewPrivileges=), scored bysystemd-analyze security. - Under the hood, boot is a chain of targets, enabling is a symlink in a
.wantsdirectory, control happens over D-Bus, and cgroups make sure no process escapes. - It is not one binary but a whole suite that also took over logging, sessions, networking, DNS, time sync, and device management.
This is the quick reference worth keeping:
ps -p 1 -o comm= confirm systemd is PID 1
systemctl status a tree of the whole running system
systemctl status nginx is one service running and enabled
systemctl list-units every unit loaded now
systemctl list-unit-files every installed unit and its state
systemctl list-timers scheduled timer units
systemctl get-default the target the system boots into
systemctl daemon-reload re-read unit files after editing
systemctl --user status your own per-user services
systemd-analyze how long the last boot took
systemd-analyze blame slowest units at boot
systemd-analyze critical-chain the chain that gated boot
systemd-analyze security nginx score a service's sandboxing
systemd-cgls the control-group tree
systemd-cgtop live CPU, memory, and I/O per service
journalctl -u nginx all logs for one unit
journalctl -b everything since the last boot
man systemd.unit the reference for unit options
A server that boots cleanly, restarts its own crashed services, schedules its jobs reliably, and keeps every log in one searchable place is not luck: it is systemd set up with intent. If your machines have services that quietly fail to come back after a reboot, jobs that run in cron with no trace of what happened, or a boot that no one on the team fully understands, it pays to get systemd configured correctly before the next incident, so the system behaves exactly as you expect, every time.
Back to top

Peter is a Joomla specialist and a Linux admin for fast, secure and scalable websites.


