Create the user with $HOME
at /run/<username>
and configure RuntimeDirectory
, so that systemd will create and chown
the directory automatically.
Set RuntimeDirectoryPreserve
to no
to discard its content when service stops or restarts. If you need more persistence, use StateDirectory
and /var/lib/<username>
instead.
Grant CAP_NET_BIND_SERVICE
so that the service could bind to well-known ports (0 to 1023).
[Unit]
Description=<description>
After=network.target
[Service]
Type=simple
ExecStart=<start-command>
User=<user>
Group=<user>
# Grant user writable access to home and working directory that persists until system reboot,
# because /run is a mount point of "tmpfs".
WorkingDirectory=~
RuntimeDirectory=<username>
RuntimeDirectoryPreserve=yes
# Hardening
NoNewPrivileges=true
# User isolation
PrivateTmp=yes
ProtectHome=yes
# Mount entire file system hierarchy read-only as much as possible
ProtectSystem=strict
PrivateDevices=yes
ProtectKernelTunables=yes
ProtectControlGroups=yes
ProtectProc=invisible
# Limit capabilities
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
# Grant capabilities
AmbientCapabilities=CAP_NET_BIND_SERVICE
[Install]
WantedBy=multi-user.target