Every Linux system runs one process before anything else touches the disk. What that process is, and how it talks to every other service, changed twice. This appendix covers the switch — and the day-to-day commands that came with it.
Boot, Explained
The kernel starts exactly one program before handing off control: PID 1, the init system. Every other process on the machine — every service, every login shell, every daemon — descends from it. Lesson 01's glossary called this "systemd" and moved on. Here's what came before it, and why it changed.
SysV init is the original Unix model: a fixed sequence of numbered
runlevels (0–6), each backed by shell scripts in /etc/init.d/. Boot
order came from filename prefixes — S20ssh runs before S50apache2 —
with dependency hints bolted on afterward as comment headers that a separate tool
(insserv) parsed to compute ordering. It works, and it's easy to read one
script at a time. It is also strictly sequential: nothing starts until the thing before it
finishes, whether or not the two are actually related.
A footnote, not a chapter: Upstart. Canonical shipped Upstart as Ubuntu's default init from 2006 through 2014, trading SysV's static ordering for an event-driven model. It never spread much beyond Ubuntu and its derivatives, and Ubuntu itself dropped it for systemd in 15.04. You'll see the name in old forum posts. You won't touch it on a current system.
systemd replaced both. Instead of numbered scripts, services declare
their dependencies directly, and systemd builds a dependency graph and starts everything
it safely can in parallel — which is most of why boot got faster. One command,
systemctl, front-ends the whole system instead of a family of ad hoc scripts
and helper tools. It became the default on Debian 8 (2015), Ubuntu 15.04, and RHEL 7, and
is what you're running today on Mint, Debian, and nearly everything else this course covers.
Boot Targets
systemd doesn't use runlevels internally, but it keeps compatibility names for them — targets — so old habits and old documentation still map onto something real.
| SysV runlevel | systemd target | Meaning |
|---|---|---|
| 0 | poweroff.target | Halt and power off |
| 1 / S / single | rescue.target | Single-user, maintenance mode |
| 2, 3, 4 | multi-user.target | Full multi-user, no GUI (systemd treats these three as equivalent) |
| 5 | graphical.target | Multi-user plus display manager / GUI |
| 6 | reboot.target | Reboot |
There's also emergency.target, one step below rescue.target: it
mounts almost nothing and gives you a root shell on a barely-alive system, for when
rescue.target itself won't come up cleanly.
Careful with isolate. Switching to rescue.target or
emergency.target stops most running services on the spot — including,
often, your network connection. Fine on a console in front of the machine; a bad idea
over SSH unless you're prepared to lose the session.
Under Each Service
A SysV init script is an imperative program: a case "$1" in start|stop|restart|status)
block that you write the logic for, one script per service. A systemd unit file is
declarative instead — you describe what the service needs and how it should start, and
systemd figures out the sequencing.
After= is ordering only — it says nothing starts sequencing until network.target
is up, but doesn't require it to succeed. Requires= is a hard dependency: if it
fails, this unit fails too. Wants=, far more common in practice, is the soft
version — best-effort, no failure propagation. WantedBy= in [Install]
is what systemctl enable actually acts on: it's the target that will pull this
unit in at boot.
Every unit resolves through three directories, checked in this order — the first one that has a file wins:
| Directory | Precedence | What lives here |
|---|---|---|
/etc/systemd/system/ | Highest | Admin config — enable symlinks, masks, overrides |
/run/systemd/system/ | Middle | Runtime only, volatile — cleared at reboot |
/usr/lib/systemd/system/ (/lib/ is the same directory) | Lowest | Vendor-shipped unit files, installed by packages |
To tweak one directive on a vendor unit without copying the whole file,
systemctl edit NAME creates a drop-in at
/etc/systemd/system/NAME.d/override.conf that layers on top of the original —
the vendor file stays untouched and upgrade-safe. After hand-editing or adding any unit
file directly, systemd won't notice until you tell it to:
Where It All Gets Written
SysV-era logging means rsyslog writing plain text to
/var/log/syslog, /var/log/auth.log, and friends — readable with
nothing but grep and tail, and still present on most systems today.
systemd adds journald, a structured binary journal that automatically
captures stdout/stderr from every service it manages, tagged with metadata (unit, PID,
boot ID, priority) you can query directly.
The journal may not survive a reboot. On many distros it's volatile by
default, kept only in /run/log/journal and wiped at shutdown. If you want
history across reboots — which matters the moment you're investigating anything —
sudo mkdir -p /var/log/journal && sudo systemctl restart systemd-journald
makes it persistent.
Day to Day
One command handles everything: starting and stopping a service right now, and separately, whether it starts automatically at boot.
On a system still carrying SysV habits, service NAME start and
sudo update-rc.d NAME defaults do roughly the same two jobs — worth
recognizing on older boxes, even though everything in this course uses systemd directly.
Enable, disable, and mask are three different symlink mechanisms, not three strengths of the same setting.
enable reads the unit's WantedBy= line and creates
/etc/systemd/system/<target>.wants/NAME, a symlink pointing at the
real unit file. It's a pointer, filed under whichever target should pull it in.disable deletes only that one symlink. The real unit file is untouched —
systemctl start NAME still works, and anything else's Requires=
or Wants= can still pull it in as a dependency.mask creates a symlink with the same name as the unit itself —
/etc/systemd/system/NAME → /dev/null — sitting at the same
directory tier as the vendor file it's shadowing. Since /etc/systemd/system/
outranks /usr/lib/systemd/system/, systemd now resolves the unit to
/dev/null. As far as anything trying to start it is concerned, the real unit
no longer exists.
Both enable and mask take a --runtime flag that
redirects the symlink to /run/systemd/system/ instead — same effect, but gone
at the next reboot. That's the layer most people forget to check.
Security lens. disable stops a service from autostarting,
but a dependency or a package postinst can still start it later. mask is the
stronger control — nothing can start it, period. Reach for mask when you want
a service genuinely gone. But "masked" only tells you the state, not the layer: it can be
an admin's persistent choice in /etc/, a temporary --runtime mask
in /run/ that vanishes on reboot, or a vendor package that ships the unit
pre-masked with no admin action involved at all. The same rule holds as everywhere else in
security work: an enabled or masked service you can't explain — and can't locate —
is the first thing worth investigating.
Before You Ever Touched It
A fresh install already has opinions about what should be enabled. That's not an accident —
it's presets: policy files that declare a default enable/disable state per
unit, applied automatically when a package installs, before you've ever run
systemctl enable yourself.
Vendor policy lives in /usr/lib/systemd/system-preset/*.preset; a local override
of that policy goes in /etc/systemd/system-preset/*.preset, checked first. Files
are evaluated in order, one line per unit, first match wins:
Package installers apply this policy with systemctl preset NAME — the actual
mechanism behind "this new service starts enabled by default" on a fresh system, instead of
every package's install script hardcoding an enable call. It's also a real
candidate for the alsa-utils case from earlier in this course: a preset, or a maintainer
script running a --runtime mask during a package transition, is a plausible
explanation for a masked unit with nothing to find in /etc/.
Security lens. systemctl preset-all resets every
unit on the system back to policy defaults in one shot — including anything you've
manually enabled, disabled, or masked as part of hardening. Never run it without diffing
enabled units before and after. On a security-sensitive image, the preset files are worth
reading once: they're the layer that decided what was running before you ever logged in.