Service Management
systemd Units and Targets covered how unit files are structured and how they depend on each other. Now it's time to put that knowledge into daily practice — starting, stopping, enabling .service units at boot, and checking their current state. This is one of the tasks a Linux administrator performs most often: a web server, a database, or your own backend application are all managed through exactly the same set of commands.
What You Will Learn
By the end of this article you will be able to:
- explain the difference between
systemctl start/stop/restart/reload; - configure automatic startup at boot with
enable/disable; - read every field in
systemctl statusoutput; - use script-friendly checks such as
is-active,is-enabled,is-failed; - explain why
mask/unmaskexists and how it differs fromdisable.
Starting, Stopping, and Restarting a Service
These three are self-explanatory: start starts a service, stop stops it, and restart stops it completely and starts it again. restart works for any service that reads its configuration on startup, but because it kills the process entirely before recreating it, the service is briefly unavailable, even if only for a moment.
reload, in contrast, forces a service to re-read its configuration without stopping it — the standard way to apply a configuration change with zero downtime, if the service supports it. Not every service supports reload; in that case systemctl reload nginx fails outright and restart has to be used instead.
Tip
If it's unclear whether a service supports reload, systemctl reload-or-restart nginx is a safe choice — it tries reload first and falls back to restart if that isn't possible.
Automatic Startup at Boot: enable and disable
start/stop only affect the current session — after a reboot, the service returns to whatever state it was in before. Whether a service starts automatically on every boot is controlled by a separate pair of commands:
enable creates a symlink in the appropriate target directory (for example, /etc/systemd/system/multi-user.target.wants/), based on the WantedBy= value in the unit file's [Install] section, covered in systemd Units and Targets. disable removes that symlink.
enable and start are two independent actions, which means four combinations are possible:
| State | Enabled? | Running right now? |
|---|---|---|
| Freshly installed, not yet configured | No | No |
| Started manually just to test it | No | Yes |
| Enabled for boot, but no reboot yet | Yes | No |
| Fully working, production state | Yes | Yes |
A convenient shorthand for doing both at once:
This performs enable and start in a single call — the form used most often when setting up a new service, and the same pattern used in Creating a Custom systemd Service.
Checking a Service's Status
● nginx.service - A high performance web server and reverse proxy server
Loaded: loaded (/lib/systemd/system/nginx.service; enabled; preset: enabled)
Active: active (running) since Fri 2026-07-24 09:02:11 UTC; 1h 20min ago
Docs: man:nginx(8)
Main PID: 1842 (nginx)
Tasks: 3 (limit: 4665)
Memory: 4.2M
CPU: 128ms
CGroup: /system.slice/nginx.service
├─1842 "nginx: master process /usr/sbin/nginx"
└─1843 "nginx: worker process"
The important fields:
- Loaded — whether the unit file was found, and its
enabled/disabledstate; - Active — the primary state (
active,inactive,failed) plus a more detailed state in parentheses (running,exited,dead); - Main PID — the service's primary process ID;
- CGroup — every process belonging to the service, the systemd-level view of the process tree covered in /proc Filesystem.
systemctl status also shows the last few log lines, but the full history is read with the dedicated tool covered in journalctl.
Script-Friendly Status Checks
Instead of the interactive status, when an automated script only needs an exit code, the following are more convenient:
| Command | What it returns |
|---|---|
systemctl is-active <unit> |
active/inactive/failed, with a matching exit code |
systemctl is-enabled <unit> |
enabled/disabled, with a matching exit code |
systemctl is-failed <unit> |
Returns 0 if the unit is in failed state, 1 otherwise |
These commands are the basic building block of health-check and monitoring scripts, the kind covered in the Bash Scripting Basics module — the exit code makes conditionals like if systemctl is-active --quiet nginx; then ... fi possible.
mask and unmask: Stronger than disable
disable only turns off automatic startup — the service can still be started manually with systemctl start. mask, on the other hand, symlinks the unit file to /dev/null, so it cannot be started at all, whether manually or as a dependency of another unit:
Removing the block:
mask is typically used when two services genuinely conflict (for example, apache2 and nginx both trying to bind the same port on one server), or when a security policy requires that a specific service be blocked entirely.
Common Mistakes
Enabling a Service but Forgetting to Start It
The service is enabled, but not running yet — because enable only affects the next boot. To start it immediately, use enable --now or a separate start.
Confusing restart and reload
Using restart on a high-traffic production service for a routine configuration change causes a brief outage, even if the service actually supports reload. Prefer reload or reload-or-restart whenever possible.
Confusing disable with mask
A disable-d service can still be started as a dependency by another unit (for example, via Requires=). If a service must never start under any circumstances, use mask.
Trying to enable a Unit With No [Install] Section
The unit files have no installation config (WantedBy=, RequiredBy=, Also=, Alias=
settings in the [Install] section, and DefaultInstance= for template units).
enable works by creating the symlink described by WantedBy=/RequiredBy= in the unit's [Install] section — a unit that has no such section simply cannot be enabled, and the command fails with the message above rather than silently doing nothing. The fix is to add an [Install] section (see Creating a Custom systemd Service). A unit that is only ever pulled in as a dependency of another unit legitimately has no [Install] section and is not meant to be enabled directly.
Exercises
- In a test VM, run an existing service (for example,
cron) throughstop,status,startand observe how theActivefield changes at each step. disablethe same service, reboot (or simulate it withsystemctl daemon-reload), and explain how theis-enabled/is-activeresults differ.maska harmless service, try tostartit and read the error message, then reverse it withunmask.- Write a conditional like
systemctl is-active --quiet nginx && echo "running" || echo "not running"and observe how the exit code ofis-activeis used in practice.
Verification criterion: you should be able to state, for a service in each of the four enable/running combinations from the table above, exactly which command moves it into a different combination.
Summary
start/stop/restart/reload control a service's current state, while enable/disable control its automatic startup at boot — two independent dimensions, often combined with enable --now. systemctl status gives a detailed view, while is-active/is-enabled/is-failed give short, exit-code-friendly checks for scripts. mask, unlike disable, blocks a service from starting through any path at all. The next article, Creating a Custom systemd Service, applies these same commands not to an existing service, but to a new .service file you write yourself.