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)
# /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
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.