systemctl: manage services with systemd
systemctl controls systemd, the service manager used by most major Linux distributions. It starts and stops services, decides which ones run at boot, and shows why something failed.
Everyday commands
systemctl status nginx # running? recent log lines? (q to quit)
sudo systemctl start nginx
sudo systemctl stop nginx
sudo systemctl restart nginx # stop and start
sudo systemctl reload nginx # re-read configuration without dropping connections
sudo systemctl enable nginx # start at boot
sudo systemctl enable --now nginx # start now and at boot
sudo systemctl disable --now cups # stop now and not at boot
systemctl is-active nginx # prints active/inactive (for scripts)
systemctl is-enabled nginx
The .service suffix is optional: nginx means nginx.service. Service names differ between distributions: ssh on Debian and Ubuntu, sshd on RHEL; apache2 on Debian, httpd on RHEL.
What is running, what failed
systemctl --failed # units that failed
systemctl list-units --type=service --state=running
systemctl list-unit-files --state=enabled # what starts at boot
systemctl list-timers # scheduled timers
systemctl list-dependencies multi-user.target
systemd-analyze blame | head # what slowed down the last boot
When a service fails, systemctl status name shows the last log lines; for the full story use journalctl: journalctl -u name -b.
Write a service for your own program
sudo tee /etc/systemd/system/report-api.service <<'EOF'
[Unit]
Description=Report API
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=reportapi
WorkingDirectory=/opt/report-api
ExecStart=/opt/report-api/venv/bin/python app.py
Restart=on-failure
RestartSec=5
# basic sandboxing
NoNewPrivileges=yes
ProtectSystem=strict
ReadWritePaths=/var/lib/report-api
PrivateTmp=yes
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload # needed after creating or editing unit files
sudo systemctl enable --now report-api
systemctl status report-api
systemd-analyze security report-api scores the sandboxing and suggests more settings.
Change a packaged service without editing its file
sudo systemctl edit nginx # opens an override file; add e.g.:
# [Service]
# LimitNOFILE=65536
sudo systemctl cat nginx # the unit file plus all overrides
sudo systemctl revert nginx # remove your overrides
Overrides live in /etc/systemd/system/nginx.service.d/ and survive package updates.
Timers instead of cron
A timer starts a service on a schedule, with logging in the journal, and a run missed while the machine was off is made up at the next boot (with Persistent=true):
# /etc/systemd/system/backup.timer (runs backup.service)
[Unit]
Description=Nightly backup
[Timer]
OnCalendar=*-*-* 02:30
Persistent=true
[Install]
WantedBy=timers.target
Enable it with sudo systemctl enable --now backup.timer. Check calendar expressions with systemd-analyze calendar "Mon..Fri 08:00". Classic cron still works too: see crontab.
Power and targets
sudo systemctl reboot
sudo systemctl poweroff
sudo systemctl rescue # single-user mode
systemctl get-default # graphical.target or multi-user.target
sudo systemctl set-default multi-user.target
More on targets and the old runlevels: runlevels and systemd targets.
User services
Normal users can run their own services with systemctl --user, using unit files in ~/.config/systemd/user/. To keep them running after logout, an administrator runs sudo loginctl enable-linger username.