Articles

systemd: units, targets and controlling services

Units, not processes: what systemd manages, and how systemctl controls a service.

Reading: 5 minServer & Virtualization

Article cover: systemd: units, targets and controlling services

systemd is the system and service manager: on a modern Linux host it starts and supervises almost everything. Its object is not the process but the unit — a named, typed resource described by a unit file. systemctl controls units; a target groups units to define a system state; and dependencies and start order, which people usually say in one breath, are two separate mechanisms.

unit, service, process: three different things

A process is a running program with a PID. A service is a background task in the ordinary sense. A unit is what systemd actually manages: a name, a type and a configuration file. The type is the file’s suffix — .service, .target, .socket, .timer, .mount, .device — so a unit is a service only when its suffix is .service. Not every unit runs a process: a .target only groups other units, and a .mount represents a mount point.

Unit files are found in three places, in increasing order of precedence: /usr/lib/systemd/system/ (shipped by packages), /run/systemd/system/ (created at runtime) and /etc/systemd/system/ (administrator changes). systemctl status names the file it loaded, and the Loaded: line also reports the load state — one of loaded, not-found, bad-setting, error or masked.

To change one setting you do not edit the vendor file: you add a drop-in, a file under /etc/systemd/system/<unit>.d/ ending in .conf. Only the directives it sets are overridden; the rest of the vendor file still applies. Editing the vendor file directly works until the next package update overwrites it.

targets: units that only group other units

A target groups units and names a system state. The common ones are multi-user.target (a multi-user system), graphical.target (a graphical login), rescue.target and emergency.target. A target has no process of its own; it is useful because one name can be used in Wants= or Requires= to pull in a whole set of units, and in After= or Before= to order against that set. systemctl get-default shows which target the system boots to.

requirement and ordering are not the same thing

Two settings decide whether a unit is pulled in, and two decide in what order:

  • Wants= is a weak requirement: the listed units are started if this unit starts, but if they fail, this unit still runs. It is the recommended way to hook the start-up of one unit to another.
  • Requires= is strong: if a required unit fails to activate and an After= on it is set, this unit is not started; and if the required unit is explicitly stopped, this unit is stopped too.
  • After= and Before= set ordering only. They do not pull anything in.
Wants=foo.service  (pull-in only)          both start together
        bar.service ────►
        foo.service ────►

Wants=foo.service + After=foo.service      bar waits for foo
        foo.service ────────►
        bar.service         ────────►

The classic mistake is reading Wants= as “start this first”. It orders nothing: with Wants= and no After= or Before=, both units start at the same time.

WantedBy= in the [Install] section is different again: it is not a runtime requirement but the instruction systemctl enable reads to create the boot-time symlink.

controlling a service with systemctl

Task Command
run now systemctl start foo.service
stop now systemctl stop foo.service
restart / reload systemctl restart foo.service / reload
start at boot systemctl enable foo.service
do not start at boot systemctl disable foo.service
enable and start at once systemctl enable --now foo.service
inspect systemctl status foo.service
ask, scriptably systemctl is-active / is-enabled
see what pulls what systemctl list-dependencies --after foo.service

The distinction that matters operationally is enable versus start. enable writes the symlink that makes the unit start at boot; start runs it now. A service can be running but not enabled — it works until the next reboot and then is quietly gone — or enabled but not running.

reading the status output

systemctl status foo.service prints a Loaded: line (the unit file path, plus enabled or disabled), an Active: line (state and timestamp), the Main PID, the cgroup, and the last few journal lines for the unit. Those trailing log lines are the fastest way to see why a start failed.

when it goes wrong

A service that “does not start” usually shows as Active: failed. Read the unit’s own log lines with journalctl -u foo.service -b; the usual causes are a wrong or non-absolute ExecStart, a missing file or permission, or a non-zero exit.

A masked unit cannot be started at all. A unit file that is empty (size 0) or symlinked to /dev/null has the load state masked, and systemd refuses to activate it even by hand; systemctl unmask foo.service restores it. That is why “it is disabled but still refuses to start” usually means masked.

Level and prerequisites. L2 — operational: enough to inspect units, control a service and read why it failed. Prerequisites are the Linux process model and the shell; this sheet does not re-explain them.

Where to go next

The companion sheets in this node — “Logs and the journal: what the system recorded and where to find it” and “Cron and systemd timers: scheduled work and why it fails silently” — build directly on the unit model above.

References

  • systemd — systemd.unit(5), Unit configuration — the unit file format, the [Unit] and [Install] sections, the .wants/ directory, drop-ins, unit search paths, and the definition of a masked unit.
  • systemd — systemd.target(5), Target unit configuration — targets as grouping units, with no process of their own, used in Wants=/Requires= and Before=/After=.
  • systemd — systemd.service(5), Service unit configuration — ExecStart=, the option that names the process a service unit runs.
  • systemd — systemctl(1) — start, stop, restart, reload, enable, disable, status, is-active, is-enabled and --now.
  • systemd — systemd.unit(5), Debian bookworm edition — the definition of a masked unit quoted in the body, and a second, version-pinned reading of the Requires=, Wants=, After= and Before= directives.
  • Red Hat — Configuring basic system settings, Chapter 10: Managing systemd (RHEL 9) — the common targets, the unit file directories, the systemctl status fields, and enabling versus masking a service.
Nodrius Field Kit — cover

Get the Nodrius Field Kit

Enter your email and we'll send you the complete Field Kit: eight technical resources in one download.

Your email address is sent to Nodrius and used to deliver the Field Kit to you by email. Marketing messages are separate and optional: the checkbox does not affect your download, and you are only added to our updates list if you tick it. Privacy Policy.

Privacy & cookies

This site does not use cookies, analytics or tracking, and it does not profile you. There is nothing technical to switch off, so Accept and Reject change nothing about how the site works: either choice lets you browse everything normally.

The only difference is what your browser remembers: your choice is stored on this device so this notice is not shown again. It contains no identifier, it is not shared with anyone, and the site sets no cookie for it.

What we do with your data
How your email address is used when you ask for a Resource, how long it is kept and which rights you have — in the Privacy Policy.
What the site stores in your browser
Nothing: no cookies, no local storage, no third-party content — in the Cookie Policy.