systemd has useful sandboxing and hardening directives, but they are not magic paste-in security. The right starting point is to understand what each directive restricts, apply one change at a time, and test the actual service before declaring it hardened.
For small-server operators, the first directives to learn are the ones that limit filesystem writes, home-directory access, devices, privileges, capabilities, and network families.
Why systemd hardening is worth learning
A systemd service already defines how a daemon starts, which user it runs as, and how it is supervised. Hardening directives extend that unit file so the service gets fewer ways to touch the host if it is compromised.
That is useful because many self-hosted services do not need broad access to the filesystem, devices, kernel features, or the user’s home directories. Reducing those privileges can limit damage when an application bug becomes a security problem.
The catch: services are different. A directive that is safe for one daemon may break another.
The first directives to understand
Start with directives that map cleanly to a question you can answer about the service. Avoid giant hardening blocks copied from random examples.
| Directive family | Question it answers | Why it matters |
|---|---|---|
User= and Group= |
Should this service run as root? | Non-root services have less default host power |
ProtectSystem= |
Should the service write to OS paths? | Makes parts of the filesystem read-only or stricter |
ProtectHome= |
Should it read home directories? | Blocks accidental access to user data |
PrivateTmp= |
Does it need shared /tmp? |
Gives the service a private temporary area |
NoNewPrivileges= |
Should child processes gain new privileges? | Blocks common privilege-escalation paths |
CapabilityBoundingSet= |
Which Linux capabilities are needed? | Removes powerful kernel-level privileges |
RestrictAddressFamilies= |
Which network families are needed? | Limits unusual socket families |
ReadWritePaths= |
Which paths must remain writable? | Allows narrow write access when the rest is protected |
The systemd.exec manual is the primary reference for these execution-environment and sandboxing settings. Use it over copied snippets.
Filesystem restrictions are usually the easiest win
Filesystem restrictions are often the safest first improvement because you can reason about them from the service’s data paths. If a service only needs to write under /var/lib/myapp and /var/log/myapp, it probably should not write anywhere else.
The pattern is:
- identify the service’s required state, config, cache, and log paths;
- make the broader system read-only where appropriate;
- add explicit writable paths only where needed;
- restart in a maintenance window;
- inspect logs for permission failures.
Do not skip step one. If you do not know where the service writes, hardening becomes guesswork.
Privilege restrictions need more care
Directives such as NoNewPrivileges= and CapabilityBoundingSet= can be powerful, but they require a clearer understanding of what the daemon needs from the kernel. Removing all capabilities may work for a simple web app and fail for a service that binds low ports, manages networking, or interacts with system resources.
The safe method is incremental:
- change one directive at a time;
- restart and check service logs;
- test the actual user path;
- keep rollback notes;
- avoid applying hardening to SSH or remote-access services without a second access path.
This is where a systemd tool primer helps. You need to be comfortable reading service status and logs before tightening the sandbox.
Do not harden SSH casually
SSH is your recovery path. A broken SSH service can become a lockout, especially on a remote VPS without console access.
If you are hardening SSH, use a dedicated lockout-safe process like the Ubuntu SSH hardening guide and keep a second session or provider console ready. Generic systemd sandboxing advice should not be pasted into ssh.service during a casual maintenance pass.
The same caution applies to firewalls, VPN daemons, Tailscale, WireGuard, and tunnel connectors. Hardening the thing you rely on for access is a higher-risk change.
How to decide what to apply first
Apply the directive that matches your clearest risk and has the easiest test. Small, verified restrictions beat broad, untested hardening blocks.
A practical order:
- make sure the service runs as a dedicated user where appropriate;
- restrict home-directory access if it is not needed;
- isolate temporary directories;
- restrict write paths;
- reduce capabilities only after checking requirements;
- use more advanced namespace and syscall restrictions last.
This pairs well with a small VPS exposure audit. First know what is running; then harden the services that matter.
FAQ
Is systemd-analyze security enough to harden a service?
No. It is a useful review aid, but it cannot know every service-specific requirement. Treat it as a starting point, not an automatic fix list.
Can I copy a systemd hardening block from another service?
You can use examples for learning, but do not paste them blindly. Each directive should match what your service actually needs.
Which directive should I use first?
Start with the service user and filesystem access. Those are easier to reason about and easier to verify than broad capability or syscall restrictions.
Sources
systemd.exec(5)manual pagesystemd.service(5)manual page- Rocky Linux systemd hardening guidance