The most surprising thing about systemd dynamic users is that they aren’t just for temporary services; they’re a fundamental security and resource management primitive that can make your entire system cleaner.
Let’s see it in action. Imagine you have a simple web server that needs to run as a specific user, but you don’t want to create a permanent user account for it.
# /etc/systemd/system/my-webserver.service
[Unit]
Description=My Lightweight Web Server
[Service]
User=my-webserver-user
Group=my-webserver-group
ExecStart=/usr/bin/python3 -m http.server 8000 --bind 127.0.0.1
WorkingDirectory=/srv/my-webserver
[Install]
WantedBy=multi-user.target
Normally, you’d run useradd my-webserver-user and groupadd my-webserver-group. But with dynamic users, systemd handles this for you.
To enable dynamic users for this service, you’d modify the service unit like this:
# /etc/systemd/system/my-webserver.service
[Unit]
Description=My Lightweight Web Server
[Service]
# Use dynamic user and group
DynamicUser=true
# Specify the name for the user and group to be created
User=my-webserver-user
Group=my-webserver-group
ExecStart=/usr/bin/python3 -m http.server 8000 --bind 127.0.0.1
WorkingDirectory=/srv/my-webserver
[Install]
WantedBy=multi-user.target
Now, when systemd starts my-webserver.service, it will:
- Check if a user named
my-webserver-userand a group namedmy-webserver-groupexist. - If they don’t,
systemdwill create them with UIDs and GIDs within a dynamically allocated range (typically/etc/login.defsUSERGROUPS_ENAB yesandUID_MIN/GID_MINsettings determine the range, often starting from 60000 or higher). - It will then set the ownership of the
WorkingDirectory(/srv/my-webserver) to this new user and group. - Finally, it will start the service process, running as
my-webserver-user.
This solves the problem of managing ephemeral or application-specific user accounts. Instead of cluttering /etc/passwd, /etc/group, /etc/shadow, and /etc/gshadow with single-purpose accounts that might only be needed for the lifetime of a specific service or even a single run, systemd manages their lifecycle.
The mental model here is that systemd becomes the custodian of these user accounts. When the service is stopped and disabled, systemd can optionally clean up these dynamically created users and groups, freeing up UIDs/GIDs and ensuring no stale accounts are left behind. This is controlled by the RuntimeDirectory directive, which can be set to true in the service unit. If RuntimeDirectory=true is set, systemd will create a directory under /run (e.g., /run/my-webserver-user) owned by the dynamic user, and this directory will be automatically removed when the service stops.
The actual UID and GID assigned to my-webserver-user are not fixed. They are dynamically allocated from a pool defined in /etc/login.defs. You can check the assigned UID/GID after the service has started by looking at the process:
ps aux | grep my-webserver.service
You’ll see the process running under the dynamically assigned UID. You can also inspect the user/group entries that systemd creates in memory, though they might not always persist in /etc/passwd if systemd manages them purely dynamically without creating persistent entries. The key is that the kernel sees a valid (though potentially temporary) user ID for the process.
Crucially, DynamicUser=true implies that systemd will attempt to create the user and group if they do not exist. If you only want systemd to use an existing user/group but not create it, you would omit DynamicUser=true and rely on User= and Group= with pre-created accounts. The dynamic aspect is the automatic creation and potential cleanup.
A common pattern is to combine DynamicUser=true with StateDirectory=my-webserver-data and RuntimeDirectory=my-webserver-run. StateDirectory creates a persistent directory under /var/lib (owned by the dynamic user) for application data, while RuntimeDirectory creates a temporary directory under /run (owned by the dynamic user) for runtime files like sockets or PID files. These directories are automatically managed and cleaned up by systemd alongside the dynamic user.
When you restart systemd after enabling this service, you won’t find my-webserver-user in /etc/passwd by default unless systemd is configured to create persistent entries (which is less common for the "dynamic" use case). Instead, systemd maintains its own internal mapping of these dynamically assigned UIDs/GIDs. The primary benefit is reduced administrative overhead and a cleaner system by avoiding the creation of numerous static user accounts.
The next thing you’ll likely encounter is how to manage file permissions for directories that don’t get created by systemd’s StateDirectory or RuntimeDirectory directives, but are still needed by your dynamic user.