⚙️ systemctl Quick Reference

systemctl cheat sheet / survival guide

Video: systemctl Cheat Sheet (sysadmin video)
Prefer to watch? This video runs the guide's main commands on a real Ubuntu 24.04 machine, with on-screen captions and no voiceover. Click to play, or watch it on YouTube. It is part of the Services, Storage and Security playlist.
systemctl [options] COMMAND [UNIT...]
systemctl status nginx

systemctl controls systemd, the init system and service manager on most modern Linux
distributions. It manages units: services (.service), timers (.timer), sockets (.socket),
mounts (.mount), targets (.target) and more. Unit names can drop the .service suffix.
Most commands that change things need sudo. Add --user to manage your own user units.

Check status

systemctl status nginx                 # state, PID, memory, recent log lines
systemctl is-active nginx              # prints active / inactive / failed
systemctl is-enabled nginx             # enabled / disabled / static / masked
systemctl is-failed nginx
systemctl show nginx                   # every property
systemctl show -p MainPID,ActiveState nginx
systemctl cat nginx                    # print the unit file(s), including drop-ins
systemctl list-dependencies nginx      # what it needs
systemctl list-dependencies --reverse nginx   # what needs it

Start, stop, restart

sudo systemctl start nginx             # start now
sudo systemctl stop nginx              # stop now
sudo systemctl restart nginx           # stop then start
sudo systemctl reload nginx            # re-read config without dropping connections
sudo systemctl reload-or-restart nginx # reload if supported, else restart
sudo systemctl try-restart nginx       # restart only if already running
sudo systemctl kill -s SIGTERM nginx   # send a signal to the unit's processes
sudo systemctl reset-failed            # clear the "failed" state

Start at boot

sudo systemctl enable nginx            # start at boot
sudo systemctl enable --now nginx      # enable AND start right now
sudo systemctl disable nginx           # do not start at boot
sudo systemctl disable --now nginx     # disable AND stop now
sudo systemctl mask nginx              # make it impossible to start (links to /dev/null)
sudo systemctl unmask nginx
sudo systemctl reenable nginx          # disable then enable (refreshes links)
enable/disable control boot behavior only. start/stop control what runs right now.

List units

systemctl list-units                   # loaded, active units
systemctl list-units --all             # include inactive
systemctl list-units --type=service    # only services
systemctl list-units --state=failed    # just the broken ones (also: systemctl --failed)
systemctl list-units --type=service --state=running
systemctl list-unit-files              # every unit file and whether it is enabled
systemctl list-unit-files --type=service --state=enabled
systemctl list-sockets                 # listening sockets
systemctl list-timers                  # scheduled timers and when they next fire
systemctl list-timers --all

Unit files and editing

/usr/lib/systemd/system/   (or /lib/systemd/system/)   Files installed by packages
/etc/systemd/system/                                   Your files and overrides (wins)
~/.config/systemd/user/                                Per-user units

sudo systemctl edit nginx              # create a drop-in override (recommended)
sudo systemctl edit --full nginx       # edit a full copy of the unit
sudo systemctl daemon-reload           # REQUIRED after editing or adding unit files
sudo systemctl revert nginx            # discard your overrides
systemd-analyze verify /etc/systemd/system/app.service   # check a unit file

A drop-in override (saved to /etc/systemd/system/nginx.service.d/override.conf)
[Service]
Restart=always
RestartSec=5
Environment=APP_ENV=production
To replace a list setting such as ExecStart, clear it first with an empty line: ExecStart=

A simple service unit (/etc/systemd/system/myapp.service)

[Unit]
Description=My App
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=myapp
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/run.sh
Restart=on-failure
RestartSec=5
Environment=PORT=8080
# Hardening (optional)
NoNewPrivileges=true
ProtectSystem=strict
ReadWritePaths=/var/lib/myapp

[Install]
WantedBy=multi-user.target

Then activate it:
sudo systemctl daemon-reload
sudo systemctl enable --now myapp
systemctl status myapp

A timer (a cron replacement)

# /etc/systemd/system/backup.timer
[Unit]
Description=Nightly backup

[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true

[Install]
WantedBy=timers.target

# /etc/systemd/system/backup.service (the job the timer runs)
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh

sudo systemctl enable --now backup.timer
systemd-analyze calendar "Mon *-*-* 09:00"   # test a schedule expression

Targets (runlevels)

systemctl get-default                  # boot target
sudo systemctl set-default multi-user.target    # boot to text mode
sudo systemctl set-default graphical.target     # boot to the desktop
sudo systemctl isolate rescue.target   # switch to single-user rescue mode now
multi-user.target   Normal server (no GUI)      graphical.target   With a desktop
rescue.target       Single-user mode            emergency.target   Minimal shell
poweroff.target     Shut down                   reboot.target      Reboot

Power

sudo systemctl reboot
sudo systemctl poweroff
sudo systemctl suspend
sudo systemctl hibernate
sudo systemctl halt

Logs (journalctl works hand in hand)

journalctl -u nginx                    # all logs for a unit
journalctl -u nginx -f                 # follow live
journalctl -u nginx -n 50 --no-pager   # last 50 lines
journalctl -u nginx --since "1 hour ago"
journalctl -u nginx -b                 # since this boot (-b -1 = previous boot)
journalctl -p err -b                   # errors and worse this boot
journalctl -xeu nginx                  # jump to the end with explanations after a failure
journalctl --disk-usage
sudo journalctl --vacuum-time=2weeks   # trim old logs

Boot and performance

systemd-analyze                        # total boot time
systemd-analyze blame                  # slowest units at boot
systemd-analyze critical-chain         # the chain that gated boot
systemd-analyze plot > boot.svg        # visual timeline
systemctl status                       # overall system state and process tree
systemd-cgtop                          # live CPU/memory by unit

Resource limits and sandboxing (in a unit file)

MemoryMax=512M       CPUQuota=50%       TasksMax=100
LimitNOFILE=65535    Nice=10            IOWeight=100
Change a running unit temporarily: sudo systemctl set-property nginx MemoryMax=1G

Practical one-liners

# Everything that failed
systemctl --failed

# Restart a service and watch it come up
sudo systemctl restart nginx && journalctl -u nginx -f

# Enable and start in one go
sudo systemctl enable --now docker

# Which services start at boot?
systemctl list-unit-files --type=service --state=enabled

# Which services are running right now?
systemctl list-units --type=service --state=running

# See a unit file with all overrides applied
systemctl cat nginx

# Find out why something failed
systemctl status nginx -l --no-pager
journalctl -xeu nginx

# Stop a service from ever being started (even as a dependency)
sudo systemctl mask bluetooth

# When is the next timer run?
systemctl list-timers --all

# Check a service's memory use
systemctl show nginx -p MemoryCurrent

# Run something in a temporary unit with limits
sudo systemd-run --unit=demo --property=MemoryMax=200M sleep 300

Exit codes of status

0   Active and running        3   Not running (inactive or failed)
4   No such unit

Common problems

"Unit not found"             Wrong name, or the unit file is not installed. Check systemctl list-unit-files
"Failed to start ... exit-code"   The program crashed: journalctl -xeu name
Edits ignored                Run sudo systemctl daemon-reload after changing any unit file
Service restarts in a loop   Restart=always with a crashing app: see "start request repeated too quickly"
"start-limit-hit"            Too many restarts: fix the app, then systemctl reset-failed
Starts but exits at once     Type=simple with a command that forks: use Type=forking or fix ExecStart
Cannot bind port / permission   Ports below 1024 need root or AmbientCapabilities=CAP_NET_BIND_SERVICE
Works by hand, fails as a service   Missing PATH, user, working directory or environment variables

Tips

    Use systemctl edit for changes (drop-ins) instead of editing files under /usr/lib, which packages overwrite.

    Always run sudo systemctl daemon-reload after editing unit files.

    Use enable --now to make a service both start now and start at boot.

    Use reload instead of restart when the service supports it, so connections are not dropped.

    mask is stronger than disable: a masked service cannot be started at all, even by another service.

    Read the logs (journalctl -u name) before guessing. The error is almost always there.

    Give services a dedicated user, Restart=on-failure, and sandbox options such as NoNewPrivileges and ProtectSystem.

    Prefer systemd timers over cron when you want logging, dependencies and missed-run catch-up (Persistent=true).

    Do not run systemctl isolate, poweroff or set-default on a remote server unless you are sure of the effect.