systemd Operations Manual
On this page
Separate running state, permission to start, and installation into boot targets. Examples use the system service example.service; add --user for a user service and inspect that separate manager.
| Task | Start here |
|---|---|
| Service will not start | State and evidence |
| Boot activation or blocking | Running and enabling |
| Change configuration or executable | Applying configuration |
| Timers and logs | Timers and verification |
Read state, then the exit reason
Inspect one service
# Read the unit source, runtime state, and recent logs
--no-pager prints directly. Read Loaded and its path/errors before Active and the main process. A non-active unit can make status return nonzero without a query failure.
# Compare runtime, exit result, and enablement properties
ActiveState=failed and Result=exit-code indicate process failure. ExecMainStatus is the main process status; also inspect pre-start commands where relevant.
# Read recent unit logs from this boot
-u selects the unit, -b this boot, and -n the line count. Use -b -1 for the previous boot or -f to follow live logs as alternatives.
Separate unit diagnosis from inventory
# List units currently recorded as failed
After fixing the cause, use sudo systemctl reset-failed example.service if needed to clear failure and start-limit counters. It neither repairs configuration nor starts the application.
# List loaded services including inactive entries
For installed unit files and enablement, use systemctl list-unit-files --type=service instead. Loaded units and installed files are different inventories.
| Observation | Meaning | Next check |
|---|---|---|
| active (running) | The process is running, not proof of application health | Check its listener and an application request |
| active (exited) | Often a oneshot unit with RemainAfterExit | Inspect Type, ExecStart and result |
| failed / exit-code | A failed result; reset-failed does not fix the cause | Read journal and Result, not just the final line |
| not-found | This manager did not find the unit | Check name, installation path, and --user scope |
Running and enabled are separate dimensions
start/stop changes current activity; enable/disable changes activation links. Masking blocks future starts without stopping an already running service.
| Intent | systemctl | Effect |
|---|---|---|
| Start / stop now | start / stop | Changes current runtime state |
| Install / remove target activation | enable / disable | Manages [Install] symlinks; does not start/stop by itself |
| Apply both | enable --now / disable --now | Changes both installation and runtime state |
| Block ordinary activation requests | mask / unmask | Mask points to /dev/null; stopping an active unit is separate |
Change the current runtime state
# Request an immediate start
Check manager state with systemctl is-active example.service, then test the application. Stop separately with sudo systemctl stop example.service; stopping does not disable future boot activation.
Configure activation through a target
# Install activation links without starting now
Check is-enabled afterward. Choose enable --now instead to start too. Disable removes links; disable --now also stops. Select the option matching your intent.
Inspect activation paths before masking
# Inspect reverse dependencies among loaded units
Omit --reverse to inspect its dependencies, and check sockets/timers too. This is not exhaustive static analysis of unloaded units. Use sudo systemctl mask example.service only to block activation; unmask reverses it. Verify is-enabled.
A disabled service can still start manually or through dependencies, sockets, or timers. A static unit usually has no [Install] instructions. Masking can conflict with an existing local unit file; inspect it instead of overwriting it.
Unit file or application configuration?
| Change | Action | Verify |
|---|---|---|
| Manually edited unit / drop-in | daemon-reload | Inspect parsed values with show; restart when new process settings are needed |
| Application configuration | reload | Requires reload support; connection behavior depends on the application |
| Need a new process | restart | Stops and starts; allow for interruption |
Inspect before adding an override
# Show the unit and each drop-in source
Record original values and paths instead of editing distribution-owned files directly. Cat shows disk files; show reports the manager’s loaded properties.
# Create or edit a local drop-in
Put the following Service fragment in the editor’s active region and save. To cancel, quit without saving. Roll back only this change’s drop-in, then reload/restart and verify; preserve unrelated overrides.
[Service]
Environment=LOG_LEVEL=debug
Restart=on-failure
RestartSec=5s
After a successful systemctl edit, the manager normally reloads unit definitions automatically; manual file edits require daemon-reload. To replace a single ExecStart, clear it with an empty assignment before adding the new command. Keep the actual service arguments.
Validate and load manually edited units
# Validate this local unit and resolvable dependencies
Use the actual main unit path from cat; editing a vendor unit does not create a full main file under /etc. Fix validation errors first. Passing does not validate application configuration.
# Reload manually edited unit definitions into the manager
This does not recreate service processes. A successful systemctl edit normally already performs the equivalent reload.
# Check the manager’s effective properties
Once correct, restart only if a new process is required, then check status/journal and requests. For application configuration supporting reload, choose sudo systemctl reload example.service instead. Do not run both mechanically.
The user manager has separate state
# Query the user service in the intended user session
User units commonly live in ~/.config/systemd/user/. Run edit/reload/enable --now as that user and inspect journalctl --user -u example.service. Adding sudo may target root’s user manager instead.
Use systemctl --user and journalctl --user for user services. loginctl enable-linger USER allows the user manager to run without an active login; enabling an individual service is a separate operation.
Timers: trigger and execution result
# /etc/systemd/system/example.timer
[Timer]
OnCalendar=daily
Persistent=true
RandomizedDelaySec=30s
[Install]
WantedBy=timers.target
# /etc/systemd/system/example.service
[Service]
Type=oneshot
ExecStart=/usr/local/bin/example-task
Provide the executable task before enabling the timer. Persistent applies to OnCalendar: reactivation can catch up a missed calendar trigger once, not replay every missed run. OnBootSec and OnUnitActiveSec are monotonic timers and do not gain this catch-up behavior.
Validate the schedule and paired units
# Inspect daily and its next scheduled elapse
Check timezone and expected timing; replace daily with the actual OnCalendar expression. Verify both files with systemd-analyze verify and ensure the task executable exists.
# Load the newly written timer and service
# Enable and activate the timer rather than manually starting the service
Persistent catch-up can run after activation; understand repeated task execution beforehand.
# Check NEXT, LAST, and the activated service
NEXT is scheduled time and LAST is activation, not success. Check the service journal and Result/ExecMainStatus. Disable scheduling with sudo systemctl disable --now example.timer; an already-running task is separate.
Separate boot timing from log retention
# Inspect the time-critical dependency chain
Correlate with journal timestamps; parallel activation and service types affect the timing interpretation.
# Measure journal usage before choosing retention
If old logs should be deleted, rotate first with sudo journalctl --rotate, then vacuum-time=7d separately. Save needed evidence first. Configure journald SystemMaxUse and related limits for ongoing retention.
An active timer does not prove the last job succeeded; inspect the service result and journal. journalctl vacuum operations remove archived journals, not a hard cap on total disk use. The blame list alone does not establish the boot critical path.