Managing Services with systemctl

Managing Services with systemctl

systemctl is the primary tool for interacting with systemd. It starts, stops, enables, disables, masks, and inspects every service, socket, timer, and target on the system. Knowing the common commands and how to read systemctl status output covers the vast majority of day-to-day service administration.

The core commands

# Start a service right now
sudo systemctl start nginx

# Stop a running service
sudo systemctl stop nginx

# Restart a service (stop then start)
sudo systemctl restart nginx

# Reload configuration without restarting (if the service supports it)
sudo systemctl reload nginx

# Reload if possible, restart if reload is not supported
sudo systemctl reload-or-restart nginx

# Enable: configure to start on boot (does not start now)
sudo systemctl enable nginx

# Disable: remove from boot (does not stop now)
sudo systemctl disable nginx

# Enable and start in one step (most common for new services)
sudo systemctl enable --now nginx

# Disable and stop in one step
sudo systemctl disable --now nginx

# Mask: prevent any start (manual or automatic)
sudo systemctl mask nginx

# Unmask: allow starting again
sudo systemctl unmask nginx

Inspecting service status

systemctl status is the most used command for diagnosing service problems:

systemctl status nginx

The output looks like this:

● nginx.service - A high performance web server and a reverse proxy server
     Loaded: loaded (/lib/systemd/system/nginx.service; enabled; preset: enabled)
     Active: active (running) since Sat 2026-06-28 10:30:00 UTC; 2h 15min ago
       Docs: man:nginx(8)
    Process: 1234 ExecStartPre=/usr/sbin/nginx -t -q ... (code=exited, status=0/SUCCESS)
   Main PID: 1235 (nginx)
      Tasks: 5 (limit: 4915)
     Memory: 12.3M
        CPU: 345ms
     CGroup: /system.slice/nginx.service
             ├─1235 "nginx: master process /usr/sbin/nginx -g daemon on..."
             ├─1236 "nginx: worker process"
             ├─1237 "nginx: worker process"
             ├─1238 "nginx: worker process"
             └─1239 "nginx: worker process"

Jun 28 10:30:00 hostname nginx[1234]: nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
Jun 28 10:30:00 hostname nginx[1234]: nginx: configuration file /etc/nginx/nginx.conf test is successful
Jun 28 10:30:00 hostname systemd[1]: Started A high performance web server and a reverse proxy server.

What to read here:

  • Loaded: the unit file path, whether it is enabled for boot, and the preset
  • Active: current state (active (running), inactive (dead), failed, activating)
  • Main PID: the primary process ID
  • CGroup: all processes belonging to this service (the full tree)
  • Memory / CPU: current resource usage
  • The log lines at the bottom: recent journal output for this unit

When a service has failed, the Active line shows failed and the log lines below usually explain why:

# A failed service example
● myapp.service - My Application
     Loaded: loaded (/etc/systemd/system/myapp.service; enabled)
     Active: failed (Result: exit-code) since Sat 2026-06-28 10:00:00 UTC; 5min ago
    Process: 9876 ExecStart=/opt/myapp/bin/myapp (code=exited, status=1/FAILURE)
   Main PID: 9876 (code=exited, status=1/FAILURE)

Jun 28 10:00:00 hostname myapp[9876]: Error: config file not found at /etc/myapp/config.toml
Jun 28 10:00:00 hostname systemd[1]: myapp.service: Main process exited, code=exited, status=1/FAILURE
Jun 28 10:00:00 hostname systemd[1]: Failed to start My Application.

Listing and filtering units

# List all loaded service units
systemctl list-units --type=service

# List only running services
systemctl list-units --type=service --state=running

# List only failed services
systemctl --failed
systemctl list-units --state=failed

# List all unit files (installed, not necessarily loaded)
systemctl list-unit-files --type=service

# List enabled services
systemctl list-unit-files --type=service --state=enabled

# List all unit types
systemctl list-units

# List socket units
systemctl list-units --type=socket

# List timer units and when they will next fire
systemctl list-timers

# Show all active timers including inactive
systemctl list-timers --all

Reading journal logs for a service

# All logs for a service
journalctl -u nginx

# Follow in real time (like tail -f)
journalctl -fu nginx

# Last 50 lines
journalctl -u nginx -n 50

# Logs since last boot
journalctl -u nginx -b

# Logs from a specific time window
journalctl -u nginx --since "1 hour ago"
journalctl -u nginx --since "2026-06-28 09:00" --until "2026-06-28 10:00"

# Show only errors and above (priority 0-3)
journalctl -u nginx -p err

# Output as JSON (includes all metadata fields)
journalctl -u nginx -o json-pretty | head -50

# Combine logs from multiple units
journalctl -u nginx -u php-fpm

Checking dependencies

# What does nginx require to start?
systemctl list-dependencies nginx

# What requires nginx?
systemctl list-dependencies --reverse nginx

# What units would be pulled in by a target?
systemctl list-dependencies multi-user.target

# Show the full dependency tree
systemctl list-dependencies --all nginx

Editing and overriding unit files

Never edit files in /lib/systemd/system/ directly — package updates overwrite them. Use overrides instead:

# Open a drop-in override (creates /etc/systemd/system/nginx.service.d/override.conf)
sudo systemctl edit nginx

# Open the full unit file for editing (replaces the package version)
sudo systemctl edit --full nginx

# After editing, always reload the daemon
sudo systemctl daemon-reload

# Show the effective unit file after overrides are applied
systemctl cat nginx

# Example drop-in to add an environment variable
# [Service]
# Environment="MY_VAR=value"

# Example drop-in to change the restart policy
# [Service]
# Restart=always
# RestartSec=10s

Managing the system state

# Reboot the system
sudo systemctl reboot

# Shut down and power off
sudo systemctl poweroff

# Suspend to RAM
sudo systemctl suspend

# Hibernate to disk
sudo systemctl hibernate

# Rescue mode (single-user, essential services only)
sudo systemctl rescue

# Emergency mode (minimal, root shell, no services)
sudo systemctl emergency

# Get/set the default target (graphical or multi-user)
systemctl get-default
sudo systemctl set-default multi-user.target

# Switch to a different target right now
sudo systemctl isolate rescue.target

User services

systemd supports per-user service management without root. User units live in ~/.config/systemd/user/ and run within the user’s session:

# Start a user service (no sudo needed)
systemctl --user start myapp

# Enable a user service to start at login
systemctl --user enable myapp

# Check user service status
systemctl --user status myapp

# Follow user service logs
journalctl --user -fu myapp

# List all user services
systemctl --user list-units --type=service

# Enable a user service to persist after logout (requires lingering)
loginctl enable-linger $USER

Lingering allows a user’s services to run even when they are not logged in, which is useful for personal bots, sync daemons, or development servers.

Environment variables in services

# Set environment variables in a unit file
# [Service]
# Environment="KEY=value"
# Environment="ANOTHER_KEY=another_value"

# Load environment variables from a file
# [Service]
# EnvironmentFile=/etc/myapp/environment

# The environment file format (one KEY=value per line, no export)
cat /etc/myapp/environment
# DATABASE_URL=postgres://localhost/mydb
# LOG_LEVEL=info

# See the effective environment of a running service
systemctl show nginx --property=Environment

Troubleshooting checklist

When a service fails to start or behaves unexpectedly:

# 1. Check the status
systemctl status servicename

# 2. Read the full journal for this unit
journalctl -u servicename -n 100 --no-pager

# 3. Check for failed units
systemctl --failed

# 4. Verify the unit file syntax
systemd-analyze verify /etc/systemd/system/myapp.service

# 5. Check what the service actually does when started
systemd-run --unit=debug-myapp /opt/myapp/bin/myapp --config /etc/myapp/config.toml

# 6. Check the boot log for early failures
journalctl -b -p 3

# 7. Check unit file overrides
systemctl cat servicename

# 8. Check dependency chain
systemctl list-dependencies servicename

# 9. Reload after any unit file changes
sudo systemctl daemon-reload

Quick reference

# Service lifecycle
sudo systemctl start svc
sudo systemctl stop svc
sudo systemctl restart svc
sudo systemctl reload svc
sudo systemctl reload-or-restart svc

# Boot configuration
sudo systemctl enable svc
sudo systemctl disable svc
sudo systemctl enable --now svc
sudo systemctl disable --now svc
sudo systemctl mask svc
sudo systemctl unmask svc

# Inspection
systemctl status svc
systemctl is-active svc
systemctl is-enabled svc
systemctl is-failed svc
journalctl -fu svc

# Listing
systemctl list-units --type=service --state=running
systemctl list-unit-files --type=service
systemctl --failed
systemctl list-timers

# Unit management
sudo systemctl edit svc           # drop-in override
sudo systemctl edit --full svc    # full replacement
sudo systemctl daemon-reload      # reload after changes
systemctl cat svc                 # show effective unit file

The enable --now and disable --now patterns are worth memorising: they are the most common operations when setting up or tearing down a service and handle both the immediate and boot-time configuration in one command.

Frequently Asked Questions

What is the difference between systemctl start and systemctl enable?

systemctl start launches the service right now, in the current boot session. It does not affect what happens on the next reboot. systemctl enable configures the service to start automatically on future boots by creating a symlink in the appropriate target directory. It does not start the service immediately. To do both at once, use systemctl enable —now, which is the most common command when setting up a new service.

What is the difference between systemctl stop and systemctl disable?

systemctl stop immediately stops the running service in the current session, but it will start again on the next reboot if it is enabled. systemctl disable removes the boot-time symlink so the service will not start on future boots, but it does not stop the currently running instance. To stop and disable at the same time, use systemctl disable —now.

What is the difference between systemctl restart and systemctl reload?

systemctl restart stops the service completely and starts it again. All active connections are dropped and all in-flight work is interrupted. systemctl reload sends SIGHUP (or a service-specific reload mechanism) to the running process, telling it to re-read its configuration without fully stopping. reload is much less disruptive but only works for services that support it. Use reload for configuration changes to services like nginx or sshd; use restart when you need a full process replacement.

How do I see why a service failed to start?

Run systemctl status servicename to see the last few log lines and the exit code. For the full log history, run journalctl -u servicename —no-pager to see all output the service has produced. journalctl -u servicename -n 50 shows the last 50 lines. If the service exits immediately, the relevant information is usually in the last few lines of the journal output for that unit.

What does systemctl mask do?

systemctl mask makes a service completely unstart-able by symlinking its unit file to /dev/null. A masked service cannot be started manually with systemctl start and cannot be pulled in as a dependency by other services. This is stronger than disable. Use masking when you want to prevent a service from ever running — for example, masking a conflicting service when you have installed an alternative. Unmask with systemctl unmask.