Linux Systemd Service Hardening Options for Network Daemons
Quick answer
Systemd can sandbox a network daemon with a few unit file options: run it as an unprivileged user, set NoNewPrivileges, make most of the filesystem read-only...
Systemd can sandbox a network daemon with a few unit file options: run it as an unprivileged user, set NoNewPrivileges, make most of the filesystem read-only with ProtectSystem, give it a private temporary directory, and drop unneeded capabilities. These options limit what an attacker can do if the service is compromised. Apply them gradually and test, because overly strict settings can break legitimate behavior.
Why Harden a Service at the Systemd Level?
Network daemons face untrusted input, so assuming that a vulnerability will eventually be found is realistic. Hardening reduces the blast radius. Even if an attacker gains code execution inside the process, restrictions enforced by the kernel through systemd limit access to files, devices, and system calls.
The advantage of doing this in the unit file is that it needs no changes to the application. The settings are declarative, easy to review, and apply to any program, including software you did not write.
You can see how exposed a unit is with the analysis command, which scores a service and lists which protections are missing. It is a useful starting point, though a perfect score is not a goal in itself.
systemd-analyze security myapi.service
Which Options Give the Most Value?
Start with options that rarely break anything, then move to stricter ones. The following unit file section shows a reasonable baseline for a typical web or API daemon.
[Service]
User=myapi
Group=myapi
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
PrivateDevices=true
ProtectKernelTunables=true
ProtectControlGroups=true
RestrictSUIDSGID=true
ReadWritePaths=/var/lib/myapi /var/log/myapi
- User and Group: never run a daemon as root unless it truly needs to.
- NoNewPrivileges: prevents the process and its children from gaining more privileges, for example through setuid binaries.
- ProtectSystem: makes system directories read-only. The strict value makes almost the whole filesystem read-only, and you list writable paths explicitly.
- ProtectHome and PrivateTmp: hide home directories and give the service its own temporary directories.
- PrivateDevices: exposes only a minimal set of device nodes.
Available options depend on your systemd version and kernel, so verify them in the systemd documentation for your distribution.
How Do Capabilities and Network Restrictions Help?
Linux splits root privileges into capabilities. A daemon that only needs to bind a low port, for example, needs a single capability instead of full root. Use AmbientCapabilities to grant what is required and CapabilityBoundingSet to cap what the service can ever hold.
- Grant only the capabilities the service uses, such as binding to privileged ports.
- Use RestrictAddressFamilies to limit which socket types the process may create.
- Consider SystemCallFilter to allow only the system calls the service normally needs, though this takes testing.
- Use IPAddressAllow and IPAddressDeny for services that should talk only to known networks, where supported.
- Set MemoryMax and TasksMax to limit damage from resource exhaustion.
Alternatively, bind to an unprivileged port and let a reverse proxy listen on the standard one. This avoids granting any special capability to the application.
How Do You Test Restrictions Without Breaking Production?
Add options in small groups and restart the service in a test environment after each change. If something fails, the journal and application logs usually show permission denied errors that point to the blocked resource.
- Use a drop-in override file to experiment, so the packaged unit file stays untouched.
- Reload the daemon configuration after editing, and restart the service.
- Exercise all features, including startup, log writing, reloads, and background jobs.
- Check that the service can still reach its dependencies, such as databases and certificate files.
- Roll out to production after a stable period in staging, with a quick rollback plan.
Document each option and why it was chosen, so future maintainers do not remove one without understanding its purpose.
Frequently Asked Questions
Does systemd hardening replace other security measures?
No. It is one layer. Keep patching, use least privilege on credentials, and secure the application itself.
What does ProtectSystem=strict break?
Writes outside allowed paths. Add the directories your service needs to ReadWritePaths or use state directory options.
Is SystemCallFilter safe to enable?
It can be, but it is the most likely to cause hard-to-diagnose failures. Start with predefined groups and test thoroughly.
How can I measure progress?
Run systemd-analyze security before and after changes to see which exposures remain.
Summary
Run daemons unprivileged, enable NoNewPrivileges, protect the filesystem, limit capabilities, and test each restriction. Use drop-ins and the analysis tool, and read the systemd documentation for your version.