BlogLinux & scripting

Sandboxing Linux services with systemd security directives

Turn a plain unit file into a locked-down sandbox with ProtectSystem, NoNewPrivileges, and capability limits.

Mar 10, 2026·11 min readAdvanced

systemd can sandbox a service without containers, SELinux modules, or code changes — just directives in the unit file. Each one removes a capability the process almost certainly does not need, and systemd-analyze security scores how far you have locked it down.

A hardened unit

/etc/systemd/system/api.service
[Service]
ExecStart=/usr/local/bin/api
DynamicUser=yes
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
PrivateDevices=yes
ReadWritePaths=/var/lib/api
CapabilityBoundingSet=
RestrictAddressFamilies=AF_INET AF_INET6
SystemCallFilter=@system-service
SystemCallErrorNumber=EPERM

What each directive buys you

Directive -> effect
Filesystem
ProtectSystem=strict -> / read-only
ProtectHome=yes -> /home hidden
PrivateTmp=yes -> isolated /tmp
ReadWritePaths -> the one exception
Privilege
NoNewPrivileges -> no setuid escalation
CapabilityBoundingSet= -> drop all caps
SystemCallFilter -> syscall allowlist
DynamicUser -> ephemeral UID

Score it

bash — before and afterlive
systemd-analyze security api.service
-> Overall exposure level: 9.6 UNSAFE (defaults)
... add the directives above, daemon-reload ...
-> Overall exposure level: 1.8 OK (hardened)
Free and reversible
These are host-native, cost nothing at runtime, and you can dial them in one at a time — start with NoNewPrivileges, ProtectSystem, and PrivateTmp.
Go deeper in a courseLinux hardeningSSH, nftables, SELinux, auditd and CIS — harden a default install.View course

Related posts