Skip to main content

Linux concept: systemd

21 July 2026

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:

SuffixUnit typeManages
.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.

Back to top

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:

NameRole
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.

Back to top

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.
EraMilestone
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 top

4. 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 top

5. 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
SectionAnswers
[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:

TargetOld runlevelMeaning
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 top

6. 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:

DirectiveEffect
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:

DirectiveEffect
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.

Back to top

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:

ComponentReplaces 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.

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 with busctl.
  • systemctl is 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.

Back to top

8. Best Practices

  • Let systemd manage your programs. A short [Unit]/[Service]/[Install] file with Restart=on-failure beats a hand-run script or an rc.local line: 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 with systemctl edit instead, so your changes survive.
  • Run daemon-reload after 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 with systemctl list-timers.
  • Sandbox internet-facing services. A few lines such as ProtectSystem=strict, PrivateTmp=true, and NoNewPrivileges=true turn many full-system compromises into contained ones. Check the result with systemd-analyze security.
  • Set resource limits on hungry services. MemoryMax= and TasksMax= stop one runaway process from taking the whole machine down.
  • Use systemd-analyze to understand your boot. blame and critical-chain show what is slow and why, instead of guessing.
  • Read the manual. systemd is thoroughly documented; man systemd, man systemd.unit, and man systemd.service are 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 top

9. Common Mistakes

9.1 Myth versus Reality

MythReality
"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-reload after 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/system or a drop-in.
  • Looking for a user service in the system view. A unit started with --user will not show under a plain systemctl status. Add --user to see it.
  • Confusing the unit name with the process name. The unit may be ssh.service while the running program is sshd. Use tab completion or systemctl list-units to find the exact unit.
  • Assuming logs live in /var/log/*.log. On a default systemd system the record is the journal; read it with journalctl, 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.
Back to top

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 systemctl and journalctl and helpers like systemd-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 systemctl to control units and journalctl to 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 by systemd-analyze security.
  • Under the hood, boot is a chain of targets, enabling is a symlink in a .wants directory, 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
Linux concept: systemd
Peter Martin
Peter Martin
Joomla Specialist

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