Unit Files — The Basic Building Block

systemd in Depth

Chapter 2 · Unit Files — The Basic Building Block

systemd1-1 established what systemd is and why it exists. This chapter gets concrete — the actual files systemd reads, and the real systemctl commands behind everything ws1 and ansible1-4 already used, unexplained.

What a Unit Is

A unit is systemd's own generic term for anything it manages — not just services, but sockets, timers, mounts, devices, and targets too (systemd1-3 covers .service in full depth, systemd1-7 covers .timer, systemd1-8 covers .socket). Every unit is described by a plain-text configuration file — its unit file.

Where Unit Files Actually Live — Location Precedence

  • /usr/lib/systemd/system/ (or /lib/systemd/system/) — units shipped by installed packages, the vendor default
  • /etc/systemd/system/ — local admin overrides and custom units, taking priority over the vendor copy
  • /run/systemd/system/ — runtime-only, volatile, never survives a reboot; used by systemd itself and some tools for temporary units

If the same unit name exists in more than one location, /etc wins over /usr/lib — a real, useful override mechanism. Copying a vendor unit into /etc/systemd/system/ and editing it there lets you customize a service without touching the original package-provided file, which a future package update would otherwise silently overwrite.

Basic Unit File Syntax — A First Look

[Unit] Description=OpenSSH server daemon [Service] ExecStart=/usr/sbin/sshd -D [Install] WantedBy=multi-user.target

Just enough to recognize the shape — systemd1-3 does the real deep dive. [Unit] holds metadata (Description=); [Service] holds the actual execution details (ExecStart=, the command actually run); [Install] controls what happens when the unit is enabled — WantedBy=multi-user.target is exactly why this note matters back in systemd1-1's own boot-target material.

systemctl — The Real Command, In Depth

  • systemctl start/stop/restart NAME — an immediate, one-time action; does not by itself survive a reboot
  • systemctl status NAME — current state, recent log lines, whether it's enabled
  • systemctl enable/disable NAME — a genuinely different axis: controls whether the unit starts automatically at the next boot, by creating or removing a symlink tied directly to the unit's own [Install]/WantedBy= line — completely independent of whether it's running right now

The real, common beginner confusion: enabling a service does not start it immediately, and starting a service does not enable it. These are two separate actions, frequently needed together.

Revealing What ansible1-4's Own service Module Wraps

ansible1-4's own service: name: nginx state: started is, underneath, literally invoking systemctl start nginx. Ansible's own idempotency check — is it already running? — corresponds directly to systemctl status being checked first, with start only actually called if genuinely needed. state: started maps to systemctl start; the module's own enabled: true option maps directly to systemctl enable. This is precisely what systemd1-1 promised, and what ansible1-1/ansible1-4 left unexplained.

ControlsSurvives a reboot on its own?
start / stop / restartWhether the unit is running right nowNo
enable / disableWhether the unit starts automatically at bootYes — that's the whole point
systemctl enable --now combines both actions
A single command that both enables (boots automatically going forward) and starts (running immediately) a unit — worth knowing, since "I enabled it but it's not running" or the reverse is a genuinely frequent point of confusion this shortcut sidesteps entirely.
Never hand-edit a unit file in /usr/lib/systemd/system/
A real mistake, in the same spirit as grub1-2's own warning against hand-editing grub.cfg — a package update can silently overwrite it. The correct place for a customization is /etc/systemd/system/, either as a full override copy, or, more surgically, via a drop-in override file — a lighter-weight option covered later in this course.

Hands-On Exercises

Exercise 1

Explain the difference between running "systemctl start nginx" and "systemctl enable nginx" on a system where nginx is currently stopped and disabled, including what happens on the next reboot in each case.

📄 View solution
Exercise 2

A unit named webapp.service exists in both /usr/lib/systemd/system/ and /etc/systemd/system/, with different ExecStart= values. Explain which one systemd actually uses, and why.

📄 View solution
Exercise 3

Explain exactly what Ansible's service module is doing internally when it runs "service: name: nginx state: started enabled: true", in terms of the two systemctl actions this chapter describes.

📄 View solution

Chapter 2 Quick Reference

  • A unit is anything systemd manages, described by a plain-text unit file (.service, .timer, .socket, ...)
  • Location precedence: /etc/systemd/system/ overrides /usr/lib/systemd/system/; /run/systemd/system/ is volatile
  • Basic unit shape: [Unit] (metadata), [Service] (execution), [Install] (enable behavior)
  • start/stop/restart — right now, doesn't survive reboot; enable/disable — automatic at boot, independent of current state
  • systemctl enable --now NAME — does both at once
  • ansible1-4's own service module is a thin wrapper: state: started → systemctl start; enabled: true → systemctl enable
  • Never hand-edit a unit file in /usr/lib/systemd/system/ — customize via /etc/systemd/system/ instead