A security-focused guide to using systemctl for Linux service management — covering service auditing, disabling unnecessary services, applying systemd sandboxing directives, and reducing the attack surface of production servers.

What is systemctl and Why Does It Matter for Security?

systemctl is the primary command-line interface to systemd, the init system and service manager used on virtually all modern Linux distributions. From a security perspective, systemctl is the authoritative tool for auditing which services are running, which are enabled to start at boot, and for applying service-level sandboxing that limits what a compromised service can do to the rest of the system. Every running service that is unnecessary represents unrealized attack surface — a potential entry point for exploitation, privilege escalation, or lateral movement. systemd also provides powerful security directives that can be applied per-unit to restrict capabilities, filesystem access, network access, and system calls — a form of built-in application containment that does not require SELinux or AppArmor expertise.

Syntax

systemctl list-units --type=service --state=running
systemctl list-units --type=service --state=enabled
systemctl list-unit-files --type=service
systemctl status <service>
systemctl disable <service>
systemctl stop <service> && systemctl disable <service>
systemctl mask <service>
systemctl show <service> | grep -i security
systemd-analyze security <service>

list-units shows active units filtered by type and state. list-unit-files shows all installed unit files and their enabled/disabled status. mask is stronger than disable — it creates a symlink to /dev/null that prevents the unit from being started manually or as a dependency. systemd-analyze security provides a security exposure score for a given service unit — the single most useful command for systematically hardening services.

Key Options and Flags

Flag / ParameterDescriptionSecurity Note
list-units --type=service --state=runningList all currently active (running) service unitsStarting point for any service audit — verify every running service is intentional
list-unit-files --type=serviceList all installed service unit files and their enabled/disabled/masked stateReveals services enabled to start at boot that may not currently be running
disable <service>Prevent a service from starting automatically at bootDoes not stop a currently running service — follow with stop for immediate effect
mask <service>Completely block a service — symlinks unit file to /dev/null, preventing any startUse for services you never want to run — stronger than disable, cannot be started as a dependency
stop <service>Immediately stop a running service—
status <service>Show current state, recent log output, and PID of a serviceReveals the UID/GID the service runs as — services running as root when not required are a hardening target
show <service>Show all properties of a service unit in machine-readable formatPipe to grep -i security to see applied security directives
systemd-analyze security <service>Score the security exposure of a unit file against systemd's built-in hardening checklistProvides per-directive recommendations — use to prioritize hardening work

Common Use Cases

Audit All Running Services and Identify Unnecessary Attack Surface

The first step in service hardening is establishing what is running and why. On a minimal production server, the list of running services should be short and every entry should have a documented reason. Services like Bluetooth, CUPS (printing), Avahi (mDNS discovery), and ModemManager are never required on a headless server and represent pure attack surface.

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

# List all enabled services (start at boot)
systemctl list-unit-files --type=service | grep enabled

# Common unnecessary services on server installs
for svc in bluetooth cups avahi-daemon ModemManager rpcbind; do
  systemctl is-active $svc 2>/dev/null && echo "RUNNING (disable): $svc"
done

Disable and Mask Unnecessary Services

Disabling a service prevents it from starting at boot. Masking goes further — it makes the service impossible to start by any means, including as a dependency of another unit. For services you are certain will never be needed (e.g., Bluetooth on a data center server), masking is the appropriate action.

# Stop and disable a service
systemctl stop bluetooth
systemctl disable bluetooth

# Mask services that should never run
systemctl mask bluetooth cups avahi-daemon ModemManager

# Verify masked status
systemctl status bluetooth
# Output should show: Loaded: masked (/dev/null; masked)

Score and Harden a Service Unit with systemd-analyze

systemd-analyze security provides a scored assessment of a service unit against systemd’s built-in security directives. A lower score means better hardening. This command identifies exactly which sandboxing options are missing, making it a practical guide for hardening any service — especially custom application units.

# Score the security exposure of nginx
systemd-analyze security nginx

# Example output (abridged):
# PrivateTmp=       UNSAFE  Service has access to other services' temporary files
# NoNewPrivileges=  UNSAFE  Service processes may acquire new privileges
# ProtectSystem=    UNSAFE  Service has write access to the OS file hierarchy
# ...
# -> Overall exposure level for nginx.service: 9.6 UNSAFE

# After adding hardening directives to the unit file:
systemd-analyze security nginx  # Re-score to verify improvement

Security Relevance: Attack Surface Reduction and Service Sandboxing

Every running service that is not required is a potential vector for exploitation. Services that listen on network sockets — even on localhost — represent remote attack surface if the network configuration changes or if another compromised process can reach them. systemd’s security directives provide a powerful, built-in mechanism for limiting what a compromised service can do: PrivateTmp=yes gives the service an isolated /tmp, preventing access to other services’ temporary files. NoNewPrivileges=yes prevents the service from gaining additional capabilities via setuid binaries. ProtectSystem=strict mounts the OS filesystem read-only for the service. PrivateNetwork=yes removes all network access. CapabilityBoundingSet= restricts which Linux capabilities the service may use. These directives do not require kernel module configuration — they are applied entirely in the unit file and take effect on the next service restart.

  • Masking a service with systemctl mask cannot be undone with enable — use systemctl unmask explicitly
  • systemctl disable removes symlinks but does not stop the service if it is currently running — always follow with stop
  • Some services have alias names — verify with systemctl list-unit-files | grep <name> to find all enabled variants
  • Adding ProtectSystem=strict or ReadOnlyPaths to a service may break it if it writes to filesystem locations you have not whitelisted — test in staging first
  • A service running as root that does not require root privileges is a privilege escalation vector — add User= and Group= directives to run it as a dedicated service account

Practical Examples

Generate a full service security audit report

echo '=== Running Services ===' > /tmp/service_audit.txt
systemctl list-units --type=service --state=running --no-pager >> /tmp/service_audit.txt

echo '\n=== Enabled at Boot ===' >> /tmp/service_audit.txt
systemctl list-unit-files --type=service | grep enabled >> /tmp/service_audit.txt

echo '\n=== Services Running as Root ===' >> /tmp/service_audit.txt
systemctl list-units --type=service --state=running --no-pager | awk '{print $1}' | \
  xargs -I{} sh -c 'u=$(systemctl show {} -p User --value); [ -z "$u" ] && echo "{} (root/default)"' \
  >> /tmp/service_audit.txt 2>/dev/null

cat /tmp/service_audit.txt

Generates a comprehensive service audit file documenting all running services, boot-enabled services, and services running without an explicit User= directive (which default to root). Review this output against your expected service list and investigate any unexpected entries.

Apply systemd security hardening to an nginx unit

# Create an override file (preferred over editing the package unit file directly)
mkdir -p /etc/systemd/system/nginx.service.d/
cat > /etc/systemd/system/nginx.service.d/hardening.conf << 'EOF'
[Service]
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/var/log/nginx /var/lib/nginx
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_SETUID CAP_SETGID
EOF

systemctl daemon-reload
systemctl restart nginx
systemd-analyze security nginx  # Verify score improved

Always use drop-in override files in /etc/systemd/system/.d/ rather than editing the package-installed unit file directly — package updates will overwrite the original file but leave your override in place. The systemd-analyze security re-run verifies the exposure score improved.

Find and investigate services listening on unexpected network ports

# List all services with open sockets
systemctl list-units --type=service --state=running --no-pager | \
  awk 'NR>1 && NF {print $1}' | \
  xargs -I{} sh -c 'ss -tlnp 2>/dev/null | grep -q $(systemctl show {} -p MainPID --value) && echo "Network: {}"' 2>/dev/null

# Cross-reference with ss output
ss -tlnp
ss -ulnp  # UDP listeners

Cross-referencing running services with their network socket exposure identifies services with unexpected listeners. A service you believe is internal-only but has a socket on 0.0.0.0 is externally exposed. Use this to verify services are listening only on intended addresses.

Troubleshooting Common Issues

Problem: systemctl disable has no effect — service still starts at boot

Solution: Check for alias unit names: systemctl list-unit-files | grep . Some services have multiple unit names; disabling one alias may not disable all. Also check if the service is enabled via a vendor preset or a socket unit: systemctl list-unit-files | grep socket. Socket-activated services start when a connection arrives even if the service unit is disabled.

Problem: systemd-analyze security is not available

Solution: systemd-analyze security requires systemd version 246 or later. Check with systemctl --version. On older systems (e.g., Ubuntu 18.04 with systemd 237), this subcommand does not exist. Upgrade to a current LTS release or manually review the security directives documented in the systemd.exec man page.

Problem: Service fails to start after adding hardening directives

Solution: Check the service journal immediately after the failure: journalctl -xe -u --no-pager | tail -30. The most common causes are: ProtectSystem=strict blocking writes to a path not in ReadWritePaths=, PrivateTmp=yes breaking services that share data via /tmp, or CapabilityBoundingSet= removing a capability the service requires. Add the required path to ReadWritePaths= or adjust the capability set, then reload and restart.

Summary

systemctl is not just a service management tool — it is a primary security hardening interface for Linux systems. The combination of auditing running services to eliminate unnecessary attack surface and applying systemd’s built-in sandboxing directives to the services that remain represents one of the highest-return hardening activities available on modern Linux. Use systemd-analyze security to score and prioritize hardening work, apply directives via drop-in override files to survive package updates, and mask services that should never run rather than simply disabling them.

  • Run systemctl list-units --type=service --state=running and verify every service has a documented reason to exist — disable and mask everything else
  • Use systemd-analyze security to get a scored, directive-level hardening roadmap for every service that must run
  • Apply hardening via drop-in files in /etc/systemd/system/.d/ — changes survive package updates and can be version-controlled

Are Your Linux Services Hardened and Audited?

INTRAM provides managed Linux server hardening including systematic service audits, unnecessary service removal, and systemd sandboxing configuration for all running services.

Request Server Hardening

Let’s assess what your business actually needs.

We will use these details only to understand your request and reply appropriately.