Most state-changing commands need ; reading status and listing units does not. Unit names can drop the suffix ( and are the same).
Manage a Service
| Command | What it does |
|---|---|
| Running or not, PID, memory, and the last ten log lines | |
| Same, full lines, no pager (for scripts and copy-paste) | |
| Start it now | |
| Stop it now | |
| Stop then start; drops connections | |
| Reload config without stopping; only for services that support it | |
| Reload if it can, otherwise restart | |
| Restart only if it is already running | |
| Prints or ; exit code 0 when running, for scripts | |
| Prints and exits 0 if it has failed | |
| Send SIGTERM to every process in the unit | |
| Send a different signal | |
| One property, here the main process ID | |
| Several properties | |
| Clear the state (and the start rate limit) | |
| Several units in one command |
and differ: sends the service its reload signal (nginx re-reads its config with no dropped connections), kills and relaunches it. exits non-zero when the service is not running, which trips up scripts that only wanted the output.
Enable and Disable
Enabling controls what happens at boot. It does not start anything on its own, and starting does not enable anything.
| Command | What it does |
|---|---|
| Start at boot (creates the symlink under ) | |
| Start at boot and start it now | |
| Do not start at boot | |
| Remove from boot and stop it now | |
| , , , , or | |
| Make it impossible to start, even by another unit (links it to ) | |
| Undo that | |
| Disable then enable; useful after the section changed | |
| Enable or disable according to the distro's preset policy |
means the unit has no section and is pulled in by something else; you cannot enable it and do not need to. means someone masked it, on purpose or by a package; restores it.
List Units
| Command | What it does |
|---|---|
| Every loaded, active unit (services, sockets, mounts, timers) | |
| Loaded services and their state | |
| Only running services | |
| Include inactive and not-found services | |
| Units that failed | |
| Same thing, shorter | |
| Every installed service file and whether it is enabled | |
| Only enabled ones | |
| Active targets (the systemd version of runlevels) | |
| Socket units and the service each one activates | |
| What nginx pulls in | |
| What depends on nginx | |
| Jobs in progress (usually empty, useful when boot hangs) | |
| Grep the output | |
| , (something failed), , or |
shows what systemd has loaded; shows what is installed on disk. A service that is installed but has never started shows up only in the second.
Logs
systemd services log to the journal, and reads it. These are the calls you need alongside systemctl; the journalctl cheat sheet covers the full toolkit.
| Command | What it does |
|---|---|
| Every log line from the nginx unit | |
| Follow live, like | |
| Last 100 lines | |
| Same, straight to the terminal | |
| Time window ( also works) | |
| Since midnight | |
| Absolute time | |
| Since the current boot | |
| From the previous boot | |
| Priority and worse (, , , ) | |
| ISO timestamps ( for structured output) | |
| Several units interleaved | |
| Recent log with explanations, what tells you to run | |
| Kernel messages only ( equivalent) | |
| How much space the journal takes | |
| Trim it to 500 MB ( by age) | |
| Boot IDs for |
shows the last ten lines. When the service failed to start and those lines do not explain why, usually does. If shows nothing for a unit, the service may be writing to its own log file under instead of stdout.
Timers
Timers are systemd's cron: a unit that starts a matching on a schedule.
| Command | What it does |
|---|---|
| Active timers with next and last run times | |
| Include inactive ones | |
| Enable and start a timer (enable the timer, not the service) | |
| Run the job now, outside the schedule | |
| When it fires next | |
| What the last runs logged | |
| Test an expression and see the next run | |
| The next five runs |
A timer that runs a script every night at 03:00, in two files:
# /etc/systemd/system/backup.service
[Unit]
Description=Nightly backup
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh# /etc/systemd/system/backup.timer
[Unit]
Description=Run backup nightly
[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true
[Install]
WantedBy=timers.targetruns a missed job at the next boot, which cron never did. Have a crontab line already? The cron to systemd timer converter turns it into these two files, and the cron generator helps with the schedule itself.
Edit Unit Files
Your units go in . Package units live in (or on Debian and Ubuntu, which is the same directory) and get overwritten on upgrade, so never edit those directly. A file in with the same name wins over the one in .
| Command | What it does |
|---|---|
| Print the unit file and every drop-in, with their paths | |
| Create or edit a drop-in override in | |
| Copy the whole unit to and edit that | |
| Create a brand new unit from scratch in your editor | |
| Delete your overrides and go back to the package's unit | |
| Re-read every unit file; required after editing one by hand | |
| Every property with its effective value | |
| What will actually run | |
| Where the unit and its overrides live | |
| Check a unit file for errors before loading it | |
| Sandboxing score and which hardening options are missing |
opens an empty drop-in in ; whatever you type is layered on top of the original, and it runs for you. It does not restart the service, so follow with . Overriding in a drop-in needs an empty line first, because lines add up:
[Service]
ExecStart=
ExecStart=/usr/sbin/nginx -c /etc/nginx/custom.confA minimal service unit for your own program:
[Unit]
Description=My app
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=app
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/bin/server --port 3000
Restart=on-failure
RestartSec=5
Environment=NODE_ENV=production
[Install]
WantedBy=multi-user.targetSave it as , then and . The systemd unit generator writes this for you and the systemd unit validator checks one you already have. Moving a Node app off pm2? The pm2 to systemd converter turns an ecosystem file into units.
Boot and Power
| Command | What it does |
|---|---|
| Reboot (same as ) | |
| Shut down and power off (same as , ) | |
| Stop the system without powering off | |
| Sleep to RAM | |
| Sleep to disk (needs swap at least the size of RAM) | |
| Both | |
| The target the system boots into ( or ) | |
| Boot to a console, no display manager | |
| Boot to a login screen | |
| Switch to that target now (stops the display manager) | |
| Single-user rescue mode | |
| Emergency shell, root filesystem read-only | |
| How long the last boot took, kernel vs userspace | |
| Every unit sorted by how long it took to start | |
| The chain of units that gated boot | |
| Boot timeline as an SVG |
shows time spent, not time that delayed the boot; a unit can take 30 seconds in parallel without slowing anything. shows the ones that actually held things up.
User Services
manages units under your own account, without , from . Handy for a personal sync client, an editor daemon, or a dev server.
| Command | What it does |
|---|---|
| Status of a user unit | |
| Enable and start it | |
| Your user services | |
| After editing a file in | |
| Drop-in override for a user unit | |
| Its logs | |
| Keep user services running when you log out, and start them at boot |
Without , user services stop when your last session closes, which is the usual reason a service dies as soon as you disconnect from SSH.
Gotchas
- is now, is at boot. A service you enabled but never started is still stopped until you reboot; does both.
- After editing any unit file by hand, run , or systemd keeps using the old version and warns . reloads for you but does not restart.
- A drop-in that sets needs on its own line first to clear the original, or the unit fails with .
- is the start rate limit, not the real error. Read for the crash that caused it, fix that, then before starting again.
- means someone ran , or the package masks it by design. first, then .
- truncates long lines and pages its output. Add when you want to copy from it or pipe it.
- means no systemd: most Docker containers, macOS, Alpine, and WSL without in . Inside a container, run the process directly and let the container's restart policy handle failures; the docker commands sheet covers that side.
- needs an absolute path and does not understand shell syntax. fails; use and , or call explicitly.