Intro
When a Linux service misbehaves, the fastest fix comes from a repeatable approach. This guide shows how to use systemctl and journalctl to find failed services, read precise logs, validate unit configuration, and restart safely. It focuses on practical commands you can copy, plus a pilot plan to test changes locally before wider use.
Workflow Overview
A safe, production-minded flow:
- Identify which units are unhealthy.
- Read detailed logs for context and timing.
- Validate the unit file and overrides.
- Apply the smallest viable fix.
- Reload and restart with guardrails.
- Confirm health and watch logs.
- Document findings and next actions.
Inspect service state with systemctl
Start with a quick health scan:
- List failed services:
systemctl --failed --type=service
- See everything by state and type:
systemctl list-units --type=service --all
- Check a specific service:
systemctl status myapp.service --no-pager -l
The output shows the active state, recent log lines, and the main PID.
For dependencies and ordering details:
- Show the dependency tree:
systemctl list-dependencies myapp.service
- Show key relations (After, Wants, Requires):
systemctl show -p After -p Wants -p Requires myapp.service
Read logs with journalctl
Use journalctl to get error details tied to time and boot.
Common patterns:
- Tail logs live:
journalctl -fu myapp.service --no-pager
- Show full context with explanations and jump to the latest entry:
journalctl -xeu myapp.service --no-pager
- Restrict to the current boot:
journalctl -u myapp.service -b --no-pager
- Previous boot for regressions:
journalctl -u myapp.service -b -1 --no-pager
- Time window:
journalctl -u myapp.service --since "2024-07-01 10:00" --until "2024-07-01 10:30" --no-pager
- Filter by priority (errors only) from the last hour:
journalctl -u myapp.service -p err --since "1 hour ago" --no-pager
If logs look sparse, ensure persistent journaling is enabled. On many systems, creating /var/log/journal and setting Storage=persistent in /etc/systemd/journald.conf, then restarting systemd-journald, will persist logs across reboots.
Validate and fix unit configuration
Confirm what systemd is actually using:
- Show the effective unit file (including drop-ins):
systemctl cat myapp.service
- Find the on-disk fragment path:
systemctl show -p FragmentPath myapp.service
- Verify syntax:
systemd-analyze verify /etc/systemd/system/myapp.service
Check common issues:
ExecStartpath or arguments wrong.- Missing
EnvironmentFileor variables. - Permissions on the executable or working directory.
User=orGroup=not allowed to access files or ports.Restart=settings causing crash loops.
Make minimal, reviewable changes with a drop-in:
systemctl edit myapp.service
This opens an override file like /etc/systemd/system/myapp.service.d/override.conf.
Example: add an environment file and slow restarts to avoid a crash loop.
[Service]
EnvironmentFile=/etc/myapp/myapp.env
Restart=on-failure
RestartSec=5s
Another concrete example: fix a wrong executable path.
[Service]
ExecStart=/usr/local/bin/myapp --config /etc/myapp/config.yaml
After editing:
systemctl daemon-reload
Restart and recover safely
Prefer the least disruptive action first:
- If supported, reload config without a full restart:
systemctl reload myapp.service
- Only if reload is not available or not sufficient, restart:
systemctl restart myapp.service
Helpful guardrails:
- Restart only if active (avoid starting disabled services unexpectedly):
systemctl try-restart myapp.service
- Clear failure counters before retrying after a backoff:
systemctl reset-failed myapp.service
Enable or disable explicitly:
- Check enablement:
systemctl is-enabled myapp.service
- Enable at boot (do not necessarily start now):
systemctl enable myapp.service
- Enable and start immediately:
systemctl enable --now myapp.service
- Disable cleanly:
systemctl disable myapp.service
Block accidental starts for broken units:
systemctl mask myapp.service
# later
systemctl unmask myapp.service
Validate recovery:
- Confirm active state:
systemctl is-active myapp.service
- Check listening ports if relevant:
ss -lntp | grep myapp
- Watch logs post-restart:
journalctl -fu myapp.service --no-pager
Local Pilot Plan
Start with a narrow, measurable pilot so you can inspect results locally before broader rollout.
Pilot goal: Prove you can identify, diagnose, and fix a single failing service safely.
Scope and steps:
- Choose a low-risk service (or a test service) on a non-critical host.
- Capture baseline:
systemctl status, last 200 log lines, and unit file contents. - Apply one minimal change (for example, fix an
EnvironmentFilepath via a drop-in). systemctl daemon-reload, thentry-restartorreload.- Validate:
is-activereturnsactive, logs show no new errors for 10 minutes, and the service performs its primary function. - Document the exact commands and outcomes so the approach is repeatable.
Success criteria:
- Measurable error resolved.
- No collateral impact on other services.
- Rollback path confirmed (remove drop-in,
daemon-reload, restart).
Optional extension:
- For timer-driven workloads, inspect timers and schedules:
systemctl list-timers --all
journalctl -u myjob.timer --no-pager
Check the paired service referenced by the timer and validate its logs and status as above.
Conclusion
A consistent flow using systemctl and journalctl shortens time to recovery: find failures fast, get precise logs, validate unit definitions, and restart with guardrails. Start with a small local pilot, prove each step, and then apply the same approach to higher-risk services. Keep changes minimal, observable, and reversible.