How to Run Service as Unprivileged User
Running service as root means one bug fit give attacker full server access. Use separate unprivileged accounts, or let systemd handle am with DynamicUser.
Why you no suppose run everything as root
Root fit do anything for the machine: read every file, change any setting, delete the whole system. When you run service as root, you give all that power to the service. If service get bug wey attacker fit exploit, dem no just get the service, dem get root, and root na the whole server. Running service as unprivileged user dey contain the damage. If service wey dey run with limited account get bug, attacker go only get wetin that account fit touch, and that one suppose nearly be nothing.
This na the principle of least privilege: give each part of the system exactly the access wey e need to do the work, and nothing more. Na the single most effective habit to limit the blast radius of compromise. For modern server, e cost almost nothing to apply am.
Account wey belong to each service
The classic way na to create separate system user for each service. Na this user go own only the files for that service, and e no fit log in. System account for web app fit look like this:
sudo useradd --system --no-create-home --shell /usr/sbin/nologin appsvcEach flag get reason. --system make am service account, no be human login. --no-create-home skip home directory wey e no need. --shell /usr/sbin/nologin mean say even if attacker somehow get the account, dem no fit open shell with am. The account dey only to own process and the files wey belong to am.
Then give that user only the files wey e need, and nothing more:
sudo chown -R appsvc:appsvc /opt/myappNow the service fit read and write for its own directory, and e no get business anywhere else for the disk. If attacker ever exploit am, the files wey dem fit change dey limited to /opt/myapp. The account still fit read anything wey everybody fit read, but e no fit modify the rest of the system.
Make systemd run am wit that user
Once the account don dey exist, tell systemd make e run the service as that user. For the unit file, na one line dey do am:
[Service]
ExecStart=/opt/myapp/bin/server
User=appsvc
Group=appsvcUser=appsvc mean say the process go start with that account limited privileges instead of root own. Na this be the normal and well-tested way to run application under systemd, and e good make you do am for every service wey you write unit for. Reducing privileges no go help if systemd dey monitor wrong process, though. So if the unit still report say e active after the daemon don quietly exit, check say you choose the correct Type= for how your process dey start.
Or skip the account entirely with DynamicUser
systemd fit go one step further and create temporary user for you, wey go only exist while the service dey run. Set DynamicUser=yes and you no need manage any account:
[Service]
ExecStart=/opt/myapp/bin/server
DynamicUser=yes
StateDirectory=myappWhen e start, systemd go allocate unused user ID; when e stop, e go release am. The service also get private /tmp, read-only view of most of the filesystem, and writable state directory under /var/lib/myapp wey StateDirectory= go set up and hand over to am. SysV init no fit do anything like this, because na each service own start script decide how to drop privileges. This limitation na major reason why distributions switch to systemd from the beginning. For self-contained service wey only need its own state directory, DynamicUser=yes na the easiest way to get strong isolation, because attacker no get any long-lived account to target.
Writing units by hand dey fiddly, and getting the hardening directives correct na where most of the value dey. Generator for the systemd service and timer guide fit fill these options for you, so the unit go correct from the first time.
How dis one take join the rest
Least privilege na one layer, and e dey work together with the others instead of replacing dem. A firewall wey deny by default controls wetin fit reach the service; running am as unprivileged user controls wetin the service fit do if dem breach am; and hardened SSH keeps attackers away from the server from the start. None of these alone dey enough, and together dem mean say bug for one service no go turn into compromise of the whole server. If you host something wey dey protect secrets, e shows where these layers stop: restricted account limits wetin breached process fit touch, but self-hosted password manager like Vaultwarden still depend on how you protect its admin token and backup file. User isolation no cover either of dem.
Before you continue, go through hardening checklist for the whole server and generate personalised copy wey you fit use:
FAQ
Why I no suppose run service as root?
Because root fit do anything for the machine, service wey dey run as root and attacker exploit am go give attacker full server access, no be only the service. If you run the service with limited, unprivileged account, the damage go stop for wetin that account fit access. Keep root for administration, and run every long-running service with restricted user.
How I fit create user wey no fit log in?
Run sudo useradd --system --no-create-home --shell /usr/sbin/nologin NAME. The nologin shell mean say the account no fit open interactive session even if person thief the credentials, --system mark am as service account, and --no-create-home skip home directory wey e no need. Give am ownership of only im own files with chown.
Wetin be systemd DynamicUser?
DynamicUser=yes tell systemd make e create temporary user for the service. The user go exist only while the service dey run, so you no need manage long-lived account. E also give the service private /tmp, filesystem view wey mostly read-only, and managed state directory. Na the easiest way to run self-contained service under temporary, low-privilege identity.
Running as non-root user replace firewall?
No. Dem protect different things. Running as unprivileged user limit wetin service fit do if attacker breach am, while firewall limit wetin fit reach the service at all. Use both, together with hardened SSH, so each layer cover wetin the others no fit cover.
Which files service user suppose own?
Na only the files wey service really need, and nothing more. Give the account ownership of im own working directory and data, then make root own everything else. One good pattern na sudo chown -R svc-app:svc-app /opt/svc-app for the application directory, while configuration under /etc remain owned by root and service only fit read am. The goal na say if person ever compromise the process, the files wey e fit change go limited to im own data, no be the rest of the system.