# systemd service management cheat sheet

> Manage services with systemctl and journalctl: start, enable, mask, unit overrides, daemon-reload, priority filters and shrinking the journal

- Page URL: https://itinsighthub.com/linux/systemd-services/
- Markdown variant of this page: append `?format=md` to any URL on this site or send `Accept: text/markdown`.
- Full site index for AI assistants: https://itinsighthub.com/llms.txt
- Full site export: https://itinsighthub.com/llms-full.txt

# systemd service management cheat sheet

systemd is PID 1 on every mainstream distro, and two tools do nearly all the work: `systemctl` changes and inspects units, `journalctl` reads their logs. This sheet keeps the two side by side because the workflow is a loop — change something, then read what happened.

Mental model that prevents most confusion: *start* affects right now, *enable* affects the next boot — neither implies the other, and `enable --now` is the usual both-at-once. Unit suffixes (`.service`) are optional when unambiguous, so `systemctl status nginx` and `systemctl status nginx.service` are the same call.

Published August 22, 2026

## systemctl: control and inspect units

*Verified against systemd v250-era behavior; rows needing root are prefixed sudo. nginx is the running example — substitute any unit*

| Task | Command | Notes |
| --- | --- | --- |
| Start a service now | sudo systemctl start nginx.service | returns once started or failed; failures surface in status |
| Stop a service | sudo systemctl stop nginx.service | running processes receive SIGTERM, then SIGKILL after the timeout |
| Restart a service | sudo systemctl restart nginx.service | full stop plus start — connections drop; prefer reload when offered |
| Reload config without restart | sudo systemctl reload nginx.service | runs the unit's ExecReload; errors if the unit defines none |
| Reload if supported, else restart | sudo systemctl reload-or-restart nginx.service | convenient in scripts; check status afterwards to know which path ran |
| Status overview | systemctl status nginx.service | loaded/enabled state, MainPID, memory, and the last log lines |
| Is it running? | systemctl is-active nginx | prints active, inactive or failed; exit code works in scripts |
| Will it start at boot? | systemctl is-enabled nginx | enabled, disabled or static — see the list-unit-files row |
| Enable start at boot | sudo systemctl enable nginx | symlinks into multi-user.target.wants; does not touch the running state |
| Enable and start together | sudo systemctl enable --now nginx | the standard post-install one-liner |
| Disable start at boot | sudo systemctl disable nginx | leaves a currently running instance alone |
| Disable and stop together | sudo systemctl disable --now nginx | the clean decommission |
| Refuse every start attempt | sudo systemctl mask nginx.service | symlinks the unit to /dev/null — stronger than disable, blocks manual starts too |
| Undo a mask | sudo systemctl unmask nginx.service | restores normal startability |
| Loaded units on the system | systemctl list-units --type=service | shows loaded, active units; add --all for inactive ones too |
| Only failed units | systemctl --failed | the first stop whenever something breaks mysteriously |
| Installed unit files and boot state | systemctl list-unit-files --type=service | static = no [Install] section, pulled in by other units rather than enabled directly |
| Show the effective unit file | systemctl cat nginx | prints the original plus every drop-in override with file paths |
| Edit a drop-in override | sudo systemctl edit nginx | opens an editor on /etc/systemd/system/nginx.service.d/override.conf; daemon-reloads on save — restart the unit yourself |
| Edit the full original unit | sudo systemctl edit --full nginx | copies the vendor file to /etc/systemd/system; prefer overrides so upgrades still apply |
| Re-read unit files from disk | sudo systemctl daemon-reload | required after hand-editing units outside systemctl edit; restarts nothing |
| Clear a stale failed state | sudo systemctl reset-failed nginx | silences the red failed banner after the actual cause is fixed |
| Query individual properties | systemctl show nginx -p MainPID,ActiveState | comma-separated property list, script-friendly single-line output |
| Show the boot target | systemctl get-default | multi-user.target = server, graphical.target = desktop; set-default switches it |
| Scheduled timers | systemctl list-timers | cron's systemd counterpart; NEXT/LAST columns expose drift |

## journalctl: read what happened

*Reads run as your user if you are in the systemd-journal, adm or wheel group; otherwise sudo. Output pages through less by default*

| Task | Command | Notes |
| --- | --- | --- |
| Logs for one unit | journalctl -u nginx.service | oldest first; press G to jump to the end or add -e to start there |
| Follow one unit live | journalctl -f -u nginx.service | the tail -f equivalent across the journal; Ctrl+C exits |
| Logs in a time window | journalctl --since "2026-08-01 09:00" --until "2026-08-01 12:00" | quoted timestamps; today, yesterday and "1 hour ago" work too |
| Errors and worse | journalctl -p err | priority err and more severe: emerg, alert, crit, err — cuts noise hard |
| Current boot only | journalctl -b | -b -1 walks one reboot back — the post-crash question |
| Kernel messages | journalctl -k | the dmesg equivalent, with proper timestamps |
| Combined triage view | journalctl -xeu nginx.service | -x extra explanation, -e end of log, -u unit filter — start debugging here |
| Pipe-friendly tail | journalctl -n 50 --no-pager | last 50 lines straight to stdout, ready for grep or redirection |
| Journal disk footprint | journalctl --disk-usage | sum of archived plus active journal files |
| Shrink the journal now | sudo journalctl --vacuum-size=200M | also --vacuum-time=2weeks; make limits permanent via journald.conf (see FAQ) |

The journal indexes by every field, so unit, priority, boot and time combine freely: journalctl -u nginx -p warning --since yesterday is a valid, common compound. If logs vanish after reboot the journal is volatile — see the FAQ on /var/log/journal.

## Anatomy of a unit file

A minimal, production-shaped service unit

```
[Unit]
Description=My API service
Wants=network-online.target
After=network-online.target

[Service]
Type=simple
User=api
WorkingDirectory=/opt/api
ExecStart=/usr/local/bin/api --port 8080
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
```

The directives that matter, by section

- **[Unit] Description=:** human-readable name shown by status and list-units
- **[Unit] After= / Before=:** pure ordering — start this unit before/after another; implies no dependency
- **[Unit] Wants= / Requires=:** dependency strength: Wants pulls in but tolerates failure; Requires fails too when the dependency fails
- **[Service] Type=:** simple (foreground, default), forking (daemonizes itself), oneshot (runs once), notify (signals readiness)
- **[Service] ExecStart= / ExecReload=:** the start command; Reload is what systemctl reload triggers, conventionally a HUP via $MAINPID
- **[Service] Restart=on-failure:** auto-restart on nonzero exit or signal; alternatives: always, no — plus RestartSec for the delay
- **[Service] User= / WorkingDirectory=:** drop privileges and anchor relative paths; omitting User means root
- **[Install] WantedBy=multi-user.target:** which target pulls the unit when enabled — multi-user for services, graphical adds display managers

## References

- [Arch Wiki: systemd](https://wiki.archlinux.org/title/Systemd) — dense, well-maintained overview of unit management commands.
- [Arch Wiki: systemd journal](https://wiki.archlinux.org/title/Systemd/Journal) — journalctl usage patterns beyond the basics.

## FAQ

**What is the difference between systemctl restart and reload?**

restart stops the service completely and starts it fresh: all connections drop, caches rebuild, downtime equals startup time. reload asks the running process to re-read its configuration (via the unit's ExecReload directive) without stopping — sockets stay open. Reload only works if the unit defines ExecReload and the application supports live reconfiguration; nginx and sshd do, many apps do not. systemctl reload-or-restart tries reload and falls back to restart.

**What is the difference between systemctl enable and start?**

start acts on right now: launches the unit immediately and forgets it at reboot. enable acts on the next boot: creates a symlink in multi-user.target.wants so the unit starts automatically, touching nothing that is currently running. A freshly installed service typically needs enable --now — enable for future boots and start for this session in one command.

**A service keeps failing — how do I debug it?**

Three steps cover most cases. First systemctl status myapp.service: it shows the recent exit code and the last log lines inline. Then journalctl -xeu myapp.service for the full annotated story around the failure — -x adds explanations, -e jumps to the end. Common causes visible right there: bad paths (WorkingDirectory or ExecStart typos), permission problems from the User= account, or a port already held by another unit (ss -tulpn confirms). After fixing, systemctl reset-failed clears the stale state before restarting.

**How do I shrink or limit journal disk usage?**

Immediately: journalctl --disk-usage shows the current footprint, and sudo journalctl --vacuum-size=200M (or --vacuum-time=2weeks) trims it on the spot. Permanently: set SystemMaxUse=200M under the [Journal] section of /etc/systemd/journald.conf, then restart systemd-journald. Without a cap the journal grows toward 10% of the filesystem, which is rarely wanted on small volumes.

**Why did my journalctl logs disappear after a reboot?**

Because the journal was volatile — stored in /run/log/journal (a tmpfs) and wiped at boot. Persistence is controlled by journald's Storage setting (default auto): create /var/log/journal, run sudo systemctl restart systemd-journald, and logs survive reboots from then on. Most server distros ship persistent by default; containers and some minimal images do not.

## Related tools

- [IPv4 subnet calculator](https://itinsighthub.com/subnet-calculator/) — break any CIDR block into network, range, broadcast and usable hosts.
- [IP range to CIDR](https://itinsighthub.com/ip-range-to-cidr/) — turn an arbitrary address range into its minimal covering CIDR blocks.
- [VLSM calculator](https://itinsighthub.com/vlsm-calculator/) — split a block into right-sized subnets by host requirements.

---

© 2026 ITInsightHub · [About](https://itinsighthub.com/about/) · [Contact](https://itinsighthub.com/contact/) · [Privacy](https://itinsighthub.com/privacy/)
