systemd Unit Builder
Generate systemd .service and .timer unit files. Hardening flags built in. Presets for web apps, periodic jobs, and one-shot tasks.
[Unit]
[Service]
Hardening
Sandbox the service. Most flags are safe for typical apps; a few break service that do unusual things — test before shipping.
[Install]
[Unit] Description=Long-running web application After=network-online.target Wants=network-online.target [Service] Type=simple ExecStart=/usr/local/bin/myapp WorkingDirectory=/var/lib/myapp User=myapp Group=myapp Restart=on-failure RestartSec=5 # Hardening NoNewPrivileges=true ProtectSystem=strict ProtectHome=true PrivateTmp=true ProtectKernelTunables=true ProtectKernelModules=true ProtectControlGroups=true [Install] WantedBy=multi-user.target
Save as /etc/systemd/system/my-app.service then run systemctl daemon-reload && systemctl enable --now my-app.service.
About this tool
systemd units are conceptually simple — three sections, key=value pairs — but in practice every flag has consequences and the hardening surface is huge. This builder gives you a form for the pieces you usually need (Description, ExecStart, User, Restart), plus a checklist of sandbox flags that improve security without breaking most services.
Three presets cover the common cases: a long-running web app (simple service, restart on failure, network-online dependency, sane hardening defaults), a periodic job (one-shot, paired with a timer), and a one-shot administrative task. Pick a preset, tweak what is wrong, copy the output.
The hardening checkboxes correspond to systemd directives that
Mozilla and the systemd developers recommend for nearly every
service. ProtectSystem=strict alone is one of the
single biggest security wins available in systemd — combined with
NoNewPrivileges and PrivateTmp, it puts
a network-facing service on solid ground without any code changes.
For timer units, OnCalendar accepts both shortcuts
(hourly, daily, weekly) and
the full form (Mon..Fri 09:00,
*-*-* 02:30:00). Test with
systemd-analyze calendar 'expression' before deploying.
Frequently asked questions
Where do I save the generated unit?
For system-wide units, /etc/systemd/system/your-app.service. For user-scoped units (managed without root), ~/.config/systemd/user/your-app.service. Run systemctl daemon-reload after creating or editing.
What is the right Type for a typical web app?
simple if your binary just runs and stays in the foreground (most modern apps). forking only if the program double-forks itself (rare nowadays). exec is like simple but waits for the binary to actually exec before considering startup complete. notify if your code calls sd_notify(READY=1) once it is up.
When should I enable each hardening flag?
Most flags are safe for typical web/API/job services. Test before shipping: ProtectKernelModules breaks anything that loads modules; PrivateDevices breaks programs that need /dev/kvm or /dev/nvidia*; MemoryDenyWriteExecute breaks JIT runtimes (Node, JVM, .NET). Mozilla Observatory and systemd-analyze security give a per-unit risk score.
How does Persistent=true on a timer work?
systemd records when each timer last ran. With Persistent=true, after a reboot or any downtime, the timer fires once if a scheduled run was missed. Without it, missed runs are silently dropped.
How do I handle environment variables that change per deployment?
Put them in a separate file (often /etc/default/your-app) and reference it with EnvironmentFile=. The Environment= field is for values you commit to source control. Don’t put secrets in unit files — use a credential manager and load with LoadCredential.