How to List, Start and Manage Services in Linux with systemctl
Every mainstream distribution (Ubuntu, Debian, RHEL and its rebuilds, Fedora, SUSE, Arch) uses systemd, so systemctl is the tool for services everywhere. Older service and chkconfig commands still exist on some systems as wrappers, but they map to systemd underneath.
List services
systemctl list-units --type=service # loaded and active services
systemctl list-units --type=service --state=running # only running ones
systemctl list-units --type=service --all # include inactive and dead
systemctl --failed # what is broken
list-units shows units systemd currently has loaded in memory. A service that is installed but disabled and never started does not appear, even with --all. To see everything installed on disk, use list-unit-files:
systemctl list-unit-files --type=service
systemctl list-unit-files --type=service --state=enabled # starts at boot
The STATE column there shows enabled, disabled, static (cannot be enabled, only started by something else) or masked (blocked from starting at all).
systemctl turns off its pager when output goes to a pipe, so grep works directly:
systemctl list-units --type=service --state=running | grep -i nginx
User services
Services started by a user session (desktop components, rootless Podman containers, systemctl --user units) live in a separate manager:
systemctl --user list-units --type=service
Which services listen on the network
From a security point of view, what listens on a port matters more than the full list:
sudo ss -tulpn
-t TCP, -u UDP, -l listening, -p process, -n numeric ports. ss replaced netstat, which is no longer installed by default on most distros.
Check one service
systemctl status nginx # state, PID, memory, last log lines
systemctl is-active nginx # prints active/inactive, exit code 0 if active
systemctl is-enabled nginx # enabled/disabled
journalctl -u nginx -f # follow its logs
journalctl -u nginx -b # logs since the last boot
is-active and is-enabled are meant for scripts: systemctl is-active --quiet nginx && echo up.
The .service suffix is optional. systemctl status nginx and systemctl status nginx.service are the same.
Start, stop, restart, enable
sudo systemctl start nginx
sudo systemctl stop nginx
sudo systemctl restart nginx
sudo systemctl reload nginx # re-read config without dropping connections, if supported
sudo systemctl enable nginx # start at boot
sudo systemctl enable --now nginx # start at boot and start right now
sudo systemctl disable --now nginx # stop and do not start at boot
sudo systemctl mask nginx # block it from being started at all
start does not survive a reboot and enable does not start anything right now. That combination trips people up. enable --now does both.
Not every service supports reload. If unsure, systemctl reload-or-restart nginx does a reload when possible and a restart otherwise.
Service names differ between distro families: ssh vs sshd, apache2 vs httpd, cron vs crond. If a name is not found, search for it:
systemctl list-unit-files --type=service | grep -Ei 'ssh|apache|httpd'
Legacy commands
sudo service nginx restart # wrapper, works on systemd and SysV systems
service --status-all # SysV-style list, incomplete on systemd systems
chkconfig --list # CentOS 6 and older
On systemd systems these redirect to systemctl. Use them only on legacy hosts that predate systemd.
Run your own program as a service
A minimal unit for an app that runs in the foreground:
# /etc/systemd/system/my-app.service
[Unit]
Description=My app
After=network-online.target
Wants=network-online.target
[Service]
User=my-app
WorkingDirectory=/opt/my-app
ExecStart=/opt/my-app/bin/server --port 8080
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now my-app
Run daemon-reload after every change to a unit file, otherwise systemd keeps using the old version. To override a packaged unit (for example, to add an environment variable), use sudo systemctl edit nginx. It creates a drop-in under /etc/systemd/system/nginx.service.d/ that survives package upgrades.
Starting Splunk as a service
Splunk Enterprise and the Splunk Universal Forwarder ship their own splunk CLI, which you use for the first start and to register a systemd unit.
First start, as the user that owns the installation:
sudo -u splunk /opt/splunk/bin/splunk start --accept-license
It asks you to create the admin user. Splunk Web then listens on port 8000.
To have systemd manage it and start it at boot, stop it and register the unit:
sudo -u splunk /opt/splunk/bin/splunk stop
sudo /opt/splunk/bin/splunk enable boot-start -systemd-managed 1 -user splunk -group splunk
sudo systemctl start Splunkd
systemctl status Splunkd
This creates Splunkd.service for Splunk Enterprise. For the Universal Forwarder, the binary is /opt/splunkforwarder/bin/splunk and the unit is SplunkForwarder.service. From then on, manage it with systemctl instead of splunk start and splunk stop, so systemd's view of the service stays correct. If it does not start, check journalctl -u Splunkd and /opt/splunk/var/log/splunk/splunkd.log.
Quick reference
systemctl list-units --type=service --state=running # running services
systemctl list-unit-files --type=service # all installed services
systemctl --failed # failed units
sudo ss -tulpn # listening services
systemctl status name # one service in detail
sudo systemctl enable --now name # start now and at boot
sudo systemctl restart name # restart
sudo systemctl daemon-reload # after editing unit files
journalctl -u name -f # follow logs
