How To

systemctl Commands to Manage Systemd Services on Linux

Every service running on a modern Linux server, from Nginx to PostgreSQL to your custom application, is managed by systemd. The tool you interact with is systemctl, and knowing it well is the difference between confidently managing a production system and fumbling through tab completion hoping for the best.

Original content from computingforgeeks.com - post 16595

This reference covers every systemctl operation you will actually use: starting and stopping services, checking status, inspecting unit files, managing boot targets, creating custom services, analyzing boot performance, and more. All commands were tested on Rocky Linux 10 with systemd 257 and apply equally to Ubuntu 24.04, Debian 13, AlmaLinux 10, and Fedora 42.

Verified working: March 2026 on Rocky Linux 10.1 (kernel 6.12), systemd 257, SELinux enforcing

Quick Reference Table

Bookmark this table. These are the commands you will reach for most often.

ActionCommand
Start a servicesystemctl start nginx
Stop a servicesystemctl stop nginx
Restart a servicesystemctl restart nginx
Reload config (no downtime)systemctl reload nginx
Enable at bootsystemctl enable nginx
Enable and start nowsystemctl enable --now nginx
Disable at bootsystemctl disable nginx
Check statussystemctl status nginx
Check if runningsystemctl is-active nginx
Check if enabledsystemctl is-enabled nginx
List running servicessystemctl list-units --type=service
List failed servicessystemctl --failed
View unit filesystemctl cat nginx
View service logsjournalctl -u nginx
Prevent service from startingsystemctl mask nginx
Reload all unit filessystemctl daemon-reload

Start, Stop, Restart, and Reload Services

These four operations are the bread and butter of service management. Start brings a service up, stop shuts it down, restart does a full stop/start cycle, and reload tells the service to re-read its configuration without dropping connections.

Start Nginx:

sudo systemctl start nginx

Stop it:

sudo systemctl stop nginx

Restart performs a full stop then start. Use this after binary upgrades or major config changes:

sudo systemctl restart nginx

Reload tells the service to re-read its configuration without stopping. Active connections stay alive. Not all services support reload, but Nginx, Apache, and most database servers do:

sudo systemctl reload nginx

When you are not sure whether a service supports reload, use reload-or-restart. It tries reload first and falls back to restart:

sudo systemctl reload-or-restart nginx

There is also try-restart, which only restarts the service if it is already running. Useful in scripts where you do not want to accidentally start a stopped service:

sudo systemctl try-restart nginx

Enable and Disable Services at Boot

Starting a service does not make it survive a reboot. You need to enable it separately. What enable actually does is create a symlink in the target directory so systemd knows to start the service during boot.

Enable Nginx to start on boot:

sudo systemctl enable nginx

The output confirms the symlink creation:

Created symlink /etc/systemd/system/multi-user.target.wants/nginx.service → /usr/lib/systemd/system/nginx.service.

The most practical variant combines both operations. Enable and start in one shot:

sudo systemctl enable --now nginx

Disable removes the symlink so the service no longer starts at boot. It does not stop a currently running service:

sudo systemctl disable nginx

To disable and stop simultaneously:

sudo systemctl disable --now nginx

Check Service Status

The status command is the single most useful systemctl subcommand. It shows whether the service is running, its PID, memory usage, CPU time, and the most recent log entries all in one view.

sudo systemctl status nginx

On Rocky Linux 10 with Nginx running:

● nginx.service - The nginx HTTP and reverse proxy server
     Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: disabled)
     Active: active (running) since Tue 2026-03-24 23:07:50 UTC; 5min ago
   Main PID: 4857 (nginx)
      Tasks: 3 (limit: 22910)
     Memory: 3.3M (peak: 6M)
        CPU: 75ms
     CGroup: /system.slice/nginx.service
             ├─4857 "nginx: master process /usr/sbin/nginx"
             ├─6086 "nginx: worker process"
             └─6087 "nginx: worker process"

The Loaded line tells you where the unit file lives and whether it is enabled. The Active line shows the current state and uptime. The CGroup tree shows every process belonging to the service, which is extremely useful when a service spawns child processes you did not expect.

Quick status checks for scripts

For scripting, use the one-word check commands. They return a clean string and set the exit code:

systemctl is-active nginx

Returns active or inactive. Check if enabled at boot:

systemctl is-enabled nginx

Check if a service has failed:

systemctl is-failed nginx

These are perfect for conditionals. The --quiet flag suppresses output and only sets the exit code:

if systemctl is-active --quiet nginx; then
  echo "Nginx is running"
fi

Check overall system health:

systemctl is-system-running

Returns running if everything is healthy, degraded if any unit failed, or initializing if the system is still booting. When it says degraded, check which unit caused it:

systemctl --failed

List Running Services and Units

See all active services on the system:

systemctl list-units --type=service --state=running

On a minimal Rocky Linux 10 server:

  UNIT                          LOAD   ACTIVE SUB     DESCRIPTION
  auditd.service                loaded active running Security Audit Logging Service
  chronyd.service               loaded active running NTP client/server
  crond.service                 loaded active running Command Scheduler
  dbus-broker.service           loaded active running D-Bus System Message Bus
  NetworkManager.service        loaded active running Network Manager
  nginx.service                 loaded active running The nginx HTTP and reverse proxy server
  rsyslog.service               loaded active running System Logging Service
  sshd.service                  loaded active running OpenSSH server daemon
  systemd-journald.service      loaded active running Journal Service
  systemd-udevd.service         loaded active running Rule-based Manager for Device Events and Files

21 loaded units listed.

Filter by other states:

systemctl list-units --type=service --state=inactive
systemctl list-units --type=service --state=failed

Show all units including sockets, mounts, and timers:

systemctl list-units --all

To see what is installed regardless of whether it is running, use list-unit-files. The STATE column shows enabled, disabled, static (cannot be enabled directly), or masked:

systemctl list-unit-files --type=service

Sample output from Rocky Linux 10:

UNIT FILE                  STATE           PRESET
auditd.service             enabled         enabled
chronyd.service            enabled         enabled
crond.service              enabled         enabled
dbus-broker.service        enabled         enabled
httpd.service              disabled        disabled
NetworkManager.service     enabled         enabled
nginx.service              enabled         disabled
sshd.service               enabled         enabled

The PRESET column shows the vendor default. When STATE differs from PRESET (like nginx above), someone manually changed it. Filter by specific state:

systemctl list-unit-files --type=service --state=enabled

Inspect Unit Files and Properties

Every service is defined by a unit file. To read the full unit file without hunting for it on disk:

systemctl cat nginx.service

This prints the file with a comment showing the path:

# /usr/lib/systemd/system/nginx.service
[Unit]
Description=The nginx HTTP and reverse proxy server
After=network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target

[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/bin/rm -f /run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/usr/sbin/nginx -s reload
KillSignal=SIGQUIT
TimeoutStopSec=5
KillMode=mixed
PrivateTmp=true

[Install]
WantedBy=multi-user.target

For specific properties, use show with the --property flag. This is far more useful than parsing status output:

systemctl show nginx.service --property=MainPID,ActiveState,SubState,MemoryCurrent

Returns clean key=value pairs, perfect for scripting:

MainPID=4857
ActiveState=active
SubState=running
MemoryCurrent=3530752

To see the full dependency tree of a service:

systemctl list-dependencies nginx.service

This reveals what the service requires and what it waits for before starting:

nginx.service
● ├─-.mount
● ├─system.slice
● ├─network-online.target
● │ └─NetworkManager-wait-online.service
● └─sysinit.target
●   ├─dev-hugepages.mount
●   ├─systemd-journald.service
●   ├─systemd-tmpfiles-setup.service
●   └─local-fs.target

Show reverse dependencies (what depends on this service):

systemctl list-dependencies nginx.service --reverse

View Service Logs with journalctl

Systemd captures all service output (stdout and stderr) in the journal. You do not need to know where a service writes its log file because journalctl has it all. For a deeper look at filtering options, see our guide on filtering systemd logs with journalctl.

Show recent logs for a service:

sudo journalctl -u nginx.service -n 20

The -n 20 flag shows the last 20 entries. Without it, you get everything since the last boot, which can be thousands of lines.

Follow logs in real time (like tail -f):

sudo journalctl -u nginx.service -f

Filter by time window:

sudo journalctl -u nginx.service --since "1 hour ago"
sudo journalctl -u nginx.service --since "2026-03-24 22:00" --until "2026-03-24 23:00"

Show only errors and above (critical, alert, emergency):

sudo journalctl -u nginx.service -p err

Priority levels go from 0 (emerg) to 7 (debug). Common filters: -p warning, -p err, -p crit.

Show logs from the current boot only:

sudo journalctl -u nginx.service -b

If your journal does not persist across reboots, configure persistent systemd journal storage so you can review logs from previous boots.

Mask and Unmask Services

Masking is stronger than disabling. A disabled service can still be started manually or pulled in as a dependency. A masked service cannot be started at all, by anyone or anything, until it is unmasked. This is how you prevent a service from running under any circumstances.

Mask a service:

sudo systemctl mask httpd.service

Systemd creates a symlink pointing to /dev/null:

Created symlink '/etc/systemd/system/httpd.service' → '/dev/null'.

Any attempt to start the masked service fails immediately:

sudo systemctl start httpd.service

The error is clear:

Failed to start httpd.service: Unit httpd.service is masked.

Unmask restores the original state:

sudo systemctl unmask httpd.service

A common use case: you have both Nginx and Apache installed but only want Nginx running. Mask Apache so nothing accidentally starts it.

Create a Custom Systemd Service

Any long-running process can become a systemd service. This gives you automatic restarts, logging via journalctl, and proper dependency ordering. For more on this topic, including running services without root privileges, see our dedicated guide.

Create the unit file:

sudo vi /etc/systemd/system/myapp.service

Add the following configuration:

[Unit]
Description=My Custom Application
After=network.target

[Service]
Type=simple
ExecStart=/usr/bin/python3 -m http.server 9090
Restart=on-failure
RestartSec=5
User=nobody
Group=nobody

[Install]
WantedBy=multi-user.target

The key directives are:

  • After – Wait for the network before starting
  • Type=simple – The process started by ExecStart is the main service process
  • Restart=on-failure – Automatically restart if the process exits with a non-zero code
  • RestartSec=5 – Wait 5 seconds before restarting
  • User/Group – Run as an unprivileged user

Reload the unit file database and start the service:

sudo systemctl daemon-reload
sudo systemctl enable --now myapp.service

Verify it is running:

sudo systemctl status myapp.service

You should see active (running) with the PID and memory usage. You can also run containers as systemd services, which is covered in our guide on running Docker and Podman containers as systemd services.

Common service types

TypeWhen to useExample
simpleProcess runs in foregroundPython scripts, Node.js apps
forkingProcess forks and parent exitsNginx, Apache
oneshotProcess runs once and exitsBackup scripts, cleanup tasks
notifyProcess signals readiness via sd_notifyPostgreSQL, systemd-aware apps
dbusProcess acquires a D-Bus nameNetworkManager, PulseAudio

Override Unit File Settings

Never edit vendor unit files in /usr/lib/systemd/system/ directly. Package updates will overwrite your changes. Instead, create a drop-in override that only replaces the specific directives you need to change.

The clean way is with systemctl edit, which creates the override directory and file for you:

sudo systemctl edit nginx.service

This opens an editor. Add the directives you want to override. For example, to increase the open file limit:

[Service]
LimitNOFILE=65536

Save and exit. Systemd creates /etc/systemd/system/nginx.service.d/override.conf and automatically runs daemon-reload. Verify the override took effect:

systemctl show nginx.service --property=LimitNOFILE

Confirms the new value:

LimitNOFILE=65536

To edit the full unit file instead of creating an override (replaces the entire file):

sudo systemctl edit --full nginx.service

To remove all overrides and revert a service to its original vendor configuration:

sudo systemctl revert nginx.service

This deletes the override directory and any full copies in /etc/systemd/system/. The service reverts to the vendor unit file.

If you create or modify unit files manually (without systemctl edit), always reload the daemon afterward:

sudo systemctl daemon-reload

Manage Systemd Timers

Systemd timers are the modern replacement for cron jobs. They offer better logging (via journalctl), dependency ordering, and the ability to catch up on missed runs. For a complete walkthrough, see our guide on configuring cron jobs with systemd timers.

List all active timers on the system:

systemctl list-timers

On Rocky Linux 10, the default installation includes several timers:

NEXT                           LEFT     LAST PASSED UNIT                         ACTIVATES
Tue 2026-03-24 23:21:28 UTC    8min     -    -      systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.service
Wed 2026-03-25 00:08:33 UTC    55min    -    -      dnf-makecache.timer          dnf-makecache.service
Wed 2026-03-25 00:18:19 UTC    1h 5min  -    -      logrotate.timer              logrotate.service
Wed 2026-03-25 00:20:45 UTC    1h 7min  -    -      fwupd-refresh.timer          fwupd-refresh.service
Sun 2026-03-29 01:00:00 UTC    4 days   -    -      raid-check.timer             raid-check.service
Mon 2026-03-30 00:33:03 UTC    5 days   -    -      fstrim.timer                 fstrim.service

6 timers listed.

The NEXT column tells you exactly when each timer fires next. The ACTIVATES column shows which service it triggers.

Include inactive timers too:

systemctl list-timers --all

Check the status of a specific timer:

systemctl status logrotate.timer

Enable or disable timers the same way as services:

sudo systemctl enable --now fstrim.timer
sudo systemctl disable --now fstrim.timer

Systemd Targets (Runlevels)

Systemd targets replace the old SysVinit runlevels. A target groups related units together and defines a system state. The two most common targets on servers are multi-user.target (text mode, no GUI) and graphical.target (with a desktop environment).

Check the current default target:

systemctl get-default

On a server, this returns:

multi-user.target

Change the default target (takes effect on next boot):

sudo systemctl set-default graphical.target
sudo systemctl set-default multi-user.target

Switch to a target immediately without rebooting:

sudo systemctl isolate multi-user.target

The isolate command stops all units not required by the target, so be careful with this on production servers.

Here is how the old runlevels map to systemd targets:

RunlevelSystemd TargetPurpose
0poweroff.targetHalt the system
1rescue.targetSingle-user mode
3multi-user.targetMulti-user, no GUI
5graphical.targetMulti-user with GUI
6reboot.targetReboot

List all available targets on the system:

systemctl list-unit-files --type=target

Analyze Boot Performance

When a server takes too long to boot, systemd-analyze tells you exactly which service is to blame.

Overall boot time breakdown:

systemd-analyze

On the test Rocky 10 VM:

Startup finished in 1.104s (kernel) + 2.452s (initrd) + 27.021s (userspace) = 30.578s
multi-user.target reached after 9.395s in userspace.

The total boot was 30 seconds, but the system was usable (multi-user.target) after 9.4 seconds. The remaining time was background services like kdump.

Find the slowest services with blame:

systemd-analyze blame

Output sorted from slowest to fastest:

17.754s kdump.service
 5.331s cloud-init-local.service
 1.244s cloud-init.service
   201ms ldconfig.service
   186ms systemd-tmpfiles-setup.service
   151ms NetworkManager-wait-online.service
    98ms rsyslog.service
    64ms NetworkManager.service
    53ms cockpit.socket

In this case, kdump.service at 17 seconds is the biggest offender. On a production server where kdump is not needed, disabling it would cut boot time in half.

See the critical chain (the sequence of units that determined overall boot time):

systemd-analyze critical-chain

This shows the longest dependency path:

multi-user.target @9.395s
└─rsyslog.service @9.288s +98ms
  └─network-online.target @9.255s
    └─cloud-init.service @8.007s +1.244s
      └─NetworkManager-wait-online.service @7.849s +151ms
        └─NetworkManager.service @7.778s +64ms
          └─network-pre.target @7.776s
            └─cloud-init-local.service @2.443s +5.331s
              └─basic.target @2.436s

Read it bottom to top. Each unit had to finish before the next one could start. The @ timestamp shows when a unit activated, and the + value shows how long it took.

Kill Service Processes

Sometimes you need to send a specific signal to a service without doing a full restart. The systemctl kill command sends a signal to all processes in the service’s cgroup.

Send SIGHUP to reload Nginx configuration (equivalent to nginx -s reload):

sudo systemctl kill nginx.service --signal=SIGHUP

Send SIGUSR1 to trigger log rotation (some services support this):

sudo systemctl kill nginx.service --signal=SIGUSR1

By default, kill sends the signal to all processes in the cgroup. To target only the main process:

sudo systemctl kill nginx.service --signal=SIGTERM --kill-whom=main

The difference between systemctl kill and systemctl stop is that kill sends a raw signal while stop follows the unit file’s ExecStop sequence, which may include graceful shutdown steps.

System Power Management

Systemctl also handles system power state transitions. These commands replace the old shutdown, halt, and reboot commands (which still work as symlinks).

Reboot the system:

sudo systemctl reboot

Power off:

sudo systemctl poweroff

Halt (stops all services but does not power off the hardware):

sudo systemctl halt

Enter rescue mode (single-user mode, for emergency maintenance):

sudo systemctl rescue

Suspend to RAM (laptop/desktop, rarely used on servers):

sudo systemctl suspend

Hibernate to disk:

sudo systemctl hibernate

Differences Between RHEL and Debian Families

The systemctl commands themselves are identical across distributions. The differences are in service names, package names, and file paths.

ItemRHEL/Rocky/AlmaLinuxUbuntu/Debian
Web server packagehttpdapache2
Web server servicehttpd.serviceapache2.service
Firewall servicefirewalld.serviceufw.service
NTP servicechronyd.servicesystemd-timesyncd.service
Unit file path (vendor)/usr/lib/systemd/system//lib/systemd/system/
Package manager timerdnf-makecache.timerapt-daily.timer
SELinux/AppArmorSELinux enforcingAppArmor enabled

The systemctl syntax does not change. Only the service name after the command differs.

Going Further

This covers the core systemctl operations. For specific use cases, these resources go deeper:

  • The official systemctl man page documents every flag and subcommand
  • Use systemctl edit to customize resource limits (CPU, memory, IO) per service via cgroup controls
  • Explore socket activation with systemctl list-sockets for on-demand service startup
  • Use systemd-cgls and systemd-cgtop for real-time cgroup resource monitoring
  • For scheduling tasks, systemd timers offer better logging and dependency handling than cron

Related Articles

Terminal How To Install Telnet on Alpine Linux Ansible Solve “[WARNING]: sftp transfer mechanism failed” in Ansible Desktop Install Chromium Browser on Ubuntu 24.04 / Linux Mint / Debian 13 Ubuntu Install KVM Virtualization on Ubuntu 24.04 (Noble Numbat)

Leave a Comment

Press ESC to close