article thumbnail

systemd

The Daemon That Became Linux's Init System, Logger, Scheduler, and More

13 min read
#ostools, #systemd, #linux, #commandlinetools, #friday2

Every Linux machine you've ever used starts the same way: the kernel boots, then hands control to exactly one process — PID 1 — whose job is to start everything else. For decades that process was a simple script runner called init. Today, on the overwhelming majority of Linux distributions, it's systemd — and "simple" is not a word anyone uses to describe it anymore. systemd doesn't just start your services; it manages logging, scheduling, mounting, networking, and device detection too. Depending on who you ask, that's either the best thing to happen to Linux administration in a decade, or a cautionary tale about scope creep. Both opinions are defensible, and you'll want to understand systemd either way — it's very likely running the machine in front of you right now.

A Brief History

Traditional Linux init (SysVinit) started services one at a time, in a fixed numeric order, using shell scripts — reliable, simple, and slow, since each service had to wait its turn even when nothing forced it to. In 2010, Lennart Poettering and Kay Sievers, both working at Red Hat, announced systemd as a replacement: an init system built around starting services in parallel wherever possible, tracking them precisely with Linux control groups (cgroups), and activating things on demand instead of unconditionally at boot.

The name follows a Unix convention — background processes ("daemons") traditionally end in d — so "system" + "d" = the daemon that manages the system. Fedora adopted it as the default in 2011; Red Hat Enterprise Linux 7, Debian, Ubuntu, SUSE, and Arch followed over the next several years. The transition wasn't quiet — Debian's 2014 decision to adopt systemd triggered enough internal disagreement that a group of developers forked the distribution into Devuan specifically to keep SysVinit alive as an option. That controversy is worth knowing about, not just as trivia: it's the direct result of systemd's central design tension, which the closing section returns to.

The Core Job: Units

systemd organizes everything it manages into units — named, typed configuration files that describe one thing to start, stop, or track. The most common unit types:

Unit type Manages
.service A long-running or one-shot program (a daemon, a script)
.socket A network or Unix socket, often paired with a .service for on-demand activation
.timer A scheduled trigger, systemd's answer to cron
.mount / .automount A filesystem mount point
.target A named grouping of other units — the modern replacement for SysVinit "runlevels"
.device A piece of hardware detected by udev

You interact with units almost entirely through one command: systemctl.

systemctl status nginx.service      # is it running? recent log lines?
systemctl start nginx.service       # start it now
systemctl stop nginx.service        # stop it now
systemctl restart nginx.service     # stop then start
systemctl enable nginx.service      # start it automatically on future boots
systemctl enable --now nginx.service # enable AND start in one command
systemctl disable nginx.service     # stop starting it automatically

enable and start are independent — this trips up nearly everyone at some point. enable wires the unit into the boot sequence for next time; start runs it right now. Doing one without the other is a common source of "but I just enabled it!" confusion.

Anatomy of a Service File

Here's a real, minimal service unit — a small web app running as its own user:

# /etc/systemd/system/myapp.service
[Unit]
Description=My Application
After=network.target

[Service]
Type=simple
User=myapp
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/bin/start.sh
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

After creating or editing a unit file, you must tell systemd to notice:

sudo systemctl daemon-reload

Forgetting this is one of the most common systemd mistakes — you edit the file, restart the service, and nothing changes, because systemd is still running on its cached copy of the old configuration. (Recent versions print a warning that the unit file changed on disk; it's easy to scroll right past.)

Targets: Runlevels, Renamed and Rebuilt

Where SysVinit had numbered runlevels (0–6), systemd has named targets that are really just units that group other units:

Target Roughly equivalent to
poweroff.target Runlevel 0
rescue.target Runlevel 1 (single-user)
multi-user.target Runlevel 3 (normal, no GUI)
graphical.target Runlevel 5 (normal, with GUI)
reboot.target Runlevel 6
systemctl get-default          # what does this machine boot into?
systemctl isolate rescue.target  # switch targets right now (careful!)

Timers: systemd's Answer to Cron

A .timer unit schedules when to run something; it pairs with a same-named .service unit (backup.timer triggers backup.service, unless you point it elsewhere with Unit=) that defines what to run:

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

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

[Install]
WantedBy=timers.target

Persistent=true is the feature plain cron never had (anacron exists to fill that gap): if the machine was off at 2am, the job runs as soon as it's back on, instead of silently skipping that day. Enable the timer (not the service) with systemctl enable --now backup.timer, and check what's scheduled with systemctl list-timers.

Socket Activation: Starting Things Lazily

A .socket unit lets systemd own a port or Unix socket before the real service is running, and start that service only the instant a connection actually arrives — the same idea inetd pioneered decades earlier, generalized across the whole system. The payoff: services that are technically "available" all the time but consume zero resources until someone actually uses them.

Reading the Logs: journalctl

systemd captures the stdout/stderr and metadata of everything it runs into a structured, indexed binary log via journald — no more hunting across a dozen text files in /var/log. (On some distributions the journal is kept only in memory and lost at reboot unless /var/log/journal exists or Storage=persistent is set in journald.conf, and many systems still run rsyslog alongside it.)

journalctl -u nginx.service          # everything logged by this one unit
journalctl -u nginx.service -f       # follow it live, like tail -f
journalctl --since "1 hour ago"
journalctl -p err                    # only error-priority messages and above
journalctl -b                        # everything since the current boot

When a service refuses to start, journalctl -xe (extra detail, jump to the end) is almost always your first move — it will usually tell you exactly which line of your unit file or which failed dependency is the actual problem.

Common Pitfalls

Tooling Worth Knowing

Command What it tells you
systemctl status <unit> Current state, recent log lines, process tree
systemctl list-units --failed Everything currently broken
systemd-analyze Total boot time
systemd-analyze blame Which units took the longest to start, sorted
systemd-analyze critical-chain The actual dependency chain that determined boot time
systemd-cgtop Live resource usage, grouped by cgroup/unit
hostnamectl / timedatectl / loginctl Hostname, clock/timezone, and login-session management, respectively

Why It Still Matters (and Why It's Still Argued About)

systemd's defenders point out, correctly, that parallel startup, dependency-aware ordering, structured logging, cgroup-based resource limits, and a consistent configuration format across distributions are genuine, measurable improvements over a pile of ad-hoc shell scripts. Its critics point out, also correctly, that a single project now controls init, logging, login sessions, network configuration (systemd-networkd), DNS resolution (systemd-resolved), and more — a lot of surface area for something whose original job was "start processes in the right order." Both things are true at once, which is exactly why the debate hasn't settled and probably won't.

What isn't in dispute: if you administer Linux servers today, you are going to meet systemd, usually while debugging why a service won't start. Learn systemctl status, journalctl -xe, and daemon-reload — that's 90% of the day-to-day, and it will save you an hour of confusion the first time a service you just edited refuses to behave.

What did you learn?

Tell us what you learned from this article, or what you liked about it. We read every comment.

Comments appear after a quick review. Please no links.

Know someone who'd love it too?

Most covered topics