Harden Linux Services with systemd Sandboxing
systemd can restrict what a service may access, even when its process is compromised. This guide tests a harmless one-shot unit, then shows how to add a small set of filesystem and privilege restrictions to a canary service. The unit settings below are examples: confirm the service’s required files, sockets, devices, and write paths before applying them.
Inspect the Unit and Record a Baseline
Read FirstChoose a noncritical system service for a later canary test. Read its effective unit and drop-ins before changing anything. Replace app.service below with a real unit name on your distribution; SSH units, for example, may be called ssh.service or sshd.service.
systemd --version | head -n 1sudo systemctl cat app.servicesudo systemd-analyze security app.service❯ Illustrative Output (Results Vary)
Review the unit's user, commands, writable paths, devices, and current sandbox settings.The security report is a checklist for review, not a pass/fail certification.Create a Harmless Sandbox Test Unit
Lab ExampleThis temporary system unit runs /usr/bin/true once under a transient, unprivileged identity. It has no application data to write, so it is a safe way to check that your systemd version accepts the example settings before you work on a real service.
# Stop if this unit name already exists; choose a new lab name instead.unit_state=$(systemctl show sandbox-demo.service -p LoadState --value)test "$unit_state" = not-found || { echo 'Unit name already exists; stop.' >&2; exit 1; }sudo test ! -e /etc/systemd/system/sandbox-demo.service || exit 1sudo test ! -L /etc/systemd/system/sandbox-demo.service || exit 1
sudo tee /etc/systemd/system/sandbox-demo.service >/dev/null <<'UNIT'[Unit]Description=Tutorial systemd sandbox demonstration
[Service]Type=oneshotDynamicUser=yesExecStart=/usr/bin/trueNoNewPrivileges=yesPrivateTmp=yesProtectHome=yesProtectSystem=strictProtectKernelTunables=yesProtectControlGroups=yesUNIT❯ Illustrative Output (Results Vary)
The command writes the temporary unit file. It does not start or enable the service.Validate the Unit Before Loading It
Configuration CheckAsk systemd to parse the file and check references, then reload the manager so it can see the new unit. A quiet verification run means the unit file passed this check; it does not prove that every sandbox feature is available in a container or that a real application will work under the restrictions.
sudo systemd-analyze verify /etc/systemd/system/sandbox-demo.servicesudo systemctl daemon-reload❯ Illustrative Output (Results Vary)
No diagnostic output is expected when the unit parses cleanly.Run the Demo and Review Its Restrictions
TestInspect the security report, run the one-shot unit, and check its recorded result. Because the command exits immediately, the unit normally returns to inactive after a successful run; use Result and ExecMainStatus to confirm the outcome.
sudo systemd-analyze security sandbox-demo.servicesudo systemctl start sandbox-demo.servicesudo systemctl show sandbox-demo.service -p Result -p ExecMainStatussudo journalctl -u sandbox-demo.service -n 10 --no-pager❯ Illustrative Output (Results Vary)
Result=successExecMainStatus=0Apply a Small Set to a Canary Service
Controlled ChangeFor a service you own, create an override rather than editing its vendor unit. Add only the settings the application can tolerate, then validate and test after a planned restart. A service using ProtectSystem=strict may need a managed state directory or a narrowly scoped writable path.
sudo systemctl edit app.serviceAdd a reviewed subset under [Service] in the editor:
[Service]NoNewPrivileges=yesPrivateTmp=yesProtectHome=yesProtectSystem=strictProtectKernelTunables=yesProtectControlGroups=yesThen validate, reload, and test during an approved maintenance window:
sudo systemd-analyze verify app.servicesudo systemctl daemon-reloadsudo systemctl restart app.servicesudo systemctl is-active app.servicesudo journalctl -u app.service -n 50 --no-pager❯ Illustrative Output (Results Vary)
Confirm the service is active and its normal health checks, logs, and client requests still succeed.Remove the Demo or Roll Back the Canary
RecoveryIf the canary fails its health checks, edit its drop-in and remove only the directives added for this test, then reload and restart it. After the lab, remove the exact tutorial unit file so it does not remain on the host.
# Lab cleanup: removes only the demo unit created in Step 2.sudo systemctl stop sandbox-demo.servicesudo systemctl reset-failed sandbox-demo.servicesudo rm /etc/systemd/system/sandbox-demo.servicesudo systemctl daemon-reload❯ Illustrative Output (Results Vary)
The temporary unit is removed from the host and systemd's unit cache is refreshed.