SYSUSERS.D(5)

okay bestie, sit down, hydrate, because sysusers.d(5) is the page where systemd just declares which system users and groups get to exist on your machine ๐Ÿ’– it's giving "spreadsheet, but it's a directory" and honestly? iconic. no cap.

๐ŸŒธ NAME ๐ŸŒธ

sysusers.d โ€” declarative allocation of system users and groups ๐Ÿ‘‘


โœจ SYNOPSIS โœจ

these are the directories it goes looking in, in case you were wondering ๐Ÿงš

/etc/sysusers.d/*.conf
/run/sysusers.d/*.conf
/usr/local/lib/sysusers.d/*.conf
/usr/lib/sysusers.d/*.conf

and here's the โœจshapeโœจ of a line โ€” one line, one user or group, periodt:

#Type Name       ID                  GECOS              Home directory Shell
u     user_name  uid                 "User Description" /home/dir      /path/to/shell
u     user_name  uid:gid             "User Description" /home/dir      /path/to/shell
u     user_name  /file/owned/by/user "User Description" /home/dir      /path/to/shell
g     group_name gid
g     group_name /file/owned/by/group
m     user_name  group_name
r     -          lowest-highest

๐Ÿ’… DESCRIPTION ๐Ÿ’…

so systemd-sysusers takes the files chillin' in the sysusers.d directory and uses them to create system users and groups, and to add users to groups โ€” either when a package gets installed, or at boot time. main character energy fr fr.

but okay, important vibe check: this tool is for allocating system users and groups only. it is not useful for creating non-system users and groups (you know, the regular, "human" ones ๐Ÿ™ˆ), because it goes straight at /etc/passwd and /etc/group directly, bypassing any more complex user databases โ€” for example any database involving NIS or LDAP. so if your users live in one of those, this is not the tool for you, bestie ๐Ÿ˜ญ


๐Ÿ—‚๏ธ CONFIGURATION DIRECTORIES AND PRECEDENCE ๐Ÿ—‚๏ธ

every config file has to be named in the style of package.conf or package-part.conf ๐Ÿ’– the second variant is the one you want when it'd be cute and convenient to override just that one part of the configuration, no biggie.

here's the tea on who wins, in order of drama:

  • files in /etc/sysusers.d override files with the same name in /usr/lib/sysusers.d and /run/sysusers.d
  • files in /run/sysusers.d override files with the same name in /usr/lib/sysusers.d
  • packages should install their configuration files in /usr/lib/sysusers.d
  • files in /etc/sysusers.d are reserved for the local administrator ๐Ÿ‘‘ who may use this logic to override the configuration files installed by vendor packages

all configuration files get sorted by their filename in lexicographic order, regardless of which of the directories they live in. and if multiple files specify the same path? the entry in the file with the lexicographically earliest name gets applied. everything after that for the same user and group names gets logged as warnings โ€” so like, the algorithm is not subtle about it, it will tell on you ๐ŸŒธ

if the administrator wants to disable a configuration file supplied by the vendor, the recommended way is to place a symlink to /dev/null in /etc/sysusers.d/ bearing the same filename. yes, really. that's the move ๐Ÿ’…


๐Ÿ“ CONFIGURATION FILE FORMAT ๐Ÿ“

the file format is one line per user or group, and each line carries: name, ID, GECOS field description, home directory, and login shell. that's it, that's the whole vibe:

#Type Name     ID             GECOS                 Home directory Shell
u!    httpd    404            "HTTP User"
u!    _authd   /usr/bin/authd "Authorization user"
u!    postgres -              "Postgresql Database" /var/lib/pgsql /usr/libexec/postgresdb
g     input    -              -
m     _authd   input
u     root     0              "Superuser"           /root          /bin/zsh
r     -        500-900

empty lines and lines beginning with the # character are ignored, and may be used for commenting ๐ŸŽ€ (yes, comment away, it's your file)

๐Ÿ”ค Type ๐Ÿ”ค

the type is literally just a single letter. here's the whole lineup, bestie:

u

create a system user and group of the specified name, should they not exist yet โœจ the user's primary group will be set to the group bearing the same name โ€” unless the ID field specifies it. the account gets created disabled, so that logins are not allowed. no sneaking in ๐Ÿ”’

added in version 215.

type u may be suffixed with an exclamation mark ("u!") to create a fully locked account ๐Ÿ”ฅ this is recommended, since logins should typically not be allowed for system users. with or without the exclamation mark, an invalid password is set. for "u!", the account is also locked โ€” and that makes a difference for non-password forms of authentication, such as SSH or similar. so like, not the same thing, don't @ me ๐Ÿ™ˆ

added in version 257.

g

create a system group of the specified name, should it not exist yet. note that u implicitly creates a matching group, so you might not even need this one ๐Ÿ‘€ the group will be created with no password set.

added in version 215.

m

add a user to a group. if the user or group do not exist yet, they will be implicitly created โ€” the system is just going to handle it for you, slay ๐Ÿซถ

added in version 215.

r

add a range of numeric UIDs/GIDs to the pool, so new UIDs and GIDs can be allocated from it. if no line of this type is specified, the range of UIDs/GIDs is set to some compiled-in default ๐ŸŽ€ note that both UIDs and GIDs are allocated from the same pool, in order to ensure that users and groups of the same name are likely to carry the same numeric UID and GID. cute, right? that's the whole point.

added in version 216.

๐Ÿท๏ธ Name ๐Ÿท๏ธ

the name field specifies the user or group name. the rules are strict and they are not playing around:

  • it must consist only of the characters a-z, A-Z, 0-9, "_" and "-"
  • the first character must be one of a-z, A-Z or "_" (i.e. numbers and "-" are not permitted as the first character)
  • the user/group name must have at least one character, and at most 31

for further details about the syntax of user/group names, see User/Group Name Syntax[1].

it is strongly recommended to pick user and group names that are unlikely to clash with normal users created by the administrator. a good scheme to guarantee this is by prefixing all system and group names with the underscore, and avoiding too generic names. do that. trust ๐Ÿ’…

for m lines, this field should contain the user name to add to a group.

for lines of type r, this field should be set to "-".

๐Ÿ”ข ID ๐Ÿ”ข

for u and g: the numeric 32-bit UID or GID of the user/group. do not use IDs 65535 or 4294967295, as they have special placeholder meanings ๐Ÿ˜ญ

  • specify "-" for automatic UID/GID allocation for the user or group โ€” this is strongly recommended unless it is strictly necessary to use a specific UID or GID
  • alternatively, specify an absolute path in the file system. in this case, the UID/GID is read from the path's owner/group. this is useful to create users whose UID/GID match the owners of pre-existing files (such as SUID or SGID binaries) ๐Ÿฆ‹
  • the syntaxes "uid:gid" and "uid:groupname" are supported, to allow creating users with specific primary groups. the given group must be created explicitly, or it must already exist. specifying "-" for the UID in these syntaxes is also supported โœจ

for m lines, this field should contain the group name to add to a user to.

for lines of type r, this field should be set to a UID/GID range in the format "FROM-TO", where both values are formatted as decimal ASCII numbers. alternatively, a single UID/GID may be specified formatted as decimal ASCII numbers.

๐Ÿ—ฃ๏ธ GECOS ๐Ÿ—ฃ๏ธ

a short, descriptive string for users to be created, enclosed in quotation marks. note that this field may not contain colons ๐Ÿ™…โ€โ™€๏ธ

only applies to lines of type u and should otherwise be left unset (or "-").

๐Ÿ  Home Directory ๐Ÿ 

the home directory for a new system user. if omitted, it defaults to the root directory.

only applies to lines of type u and should otherwise be left unset (or "-"). it is recommended to omit this, unless software strictly requires a home directory to be set. like, don't set it for funsies.

heads up bestie: systemd-sysusers only sets the home directory record in the user database. to actually create the directory, consider adding a corresponding tmpfiles.d(5) fragment ๐ŸŒธ

๐Ÿš Shell ๐Ÿš

the login shell of the user. if not specified, this will be set to /usr/sbin/nologin โ€” except if the UID of the user is 0, in which case /bin/sh will be used ๐Ÿ‘‘

only applies to lines of type u and should otherwise be left unset (or "-"). it is recommended to omit this, unless a shell different from /usr/sbin/nologin must be used.


๐ŸŒˆ SPECIFIERS ๐ŸŒˆ

specifiers can be used in the "Name", "ID", "GECOS", "Home directory", and "Shell" fields โœจ an unknown or unresolvable specifier is treated as invalid configuration โ€” so no improvising, bestie, it will simply say no ๐Ÿ’€

the following expansions are understood:

โœจ Table 1. Specifiers available โœจ

okay bestie, here's the whole specifier menu, no skips, no cuts, every single one ๐Ÿ’–

  • "%a" โ€” Architecture</p>: a short string identifying the architecture of the local system. Like x86, x86-64 or arm64. Wanna see the whole list? Check the architectures defined for ConditionArchitecture= in systemd.unit(5). ๐Ÿ‘‘
  • "%A" โ€” Operating system image version</p>: the operating system image version identifier of the running system, read straight from the IMAGE_VERSION= field of /etc/os-release. If it's not set, it resolves to an empty string. os-release(5) has the tea. ๐Ÿซถ
  • "%b" โ€” Boot ID</p>: the boot ID of the running system, formatted as a string. See random(4) for more. ๐Ÿ”ฅ
  • "%B" โ€” Operating system build ID</p>: the operating system build identifier of the running system, read from the BUILD_ID= field of /etc/os-release. Not set? Empty string, bestie. os-release(5) for more. โœจ
  • "%H" โ€” Host name</p>: the hostname of the running system. that's it, that's the whole vibe ๐ŸŽ€
  • "%l" โ€” Short host name</p>: the hostname of the running system, truncated at the first dot to remove any domain component. bye domain ๐Ÿ’…
  • "%m" โ€” Machine ID</p>: the machine ID of the running system, formatted as a string. machine-id(5) has more info. ๐Ÿ’œ
  • "%M" โ€” Operating system image identifier</p>: the operating system image identifier of the running system, read from the IMAGE_ID= field of /etc/os-release. If not set, resolves to an empty string. See os-release(5). ๐ŸŒธ
  • "%o" โ€” Operating system ID</p>: the operating system identifier of the running system, read from the ID= field of /etc/os-release. os-release(5) for more. โญ
  • "%q" โ€” Pretty host name</p>: the pretty hostname of the running system, read from the PRETTY_HOSTNAME= field of /etc/machine-info. If it's not set, it resolves to the short hostname. See machine-info(5) for more information. ๐Ÿ’–
  • "%T" โ€” Directory for temporary files</p>: this is either /tmp or whatever path "$TMPDIR", "$TEMP" or "$TMP" are set to. (heads up: the directory may be specified without a trailing slash.) ๐Ÿฆ‹
  • "%v" โ€” Kernel release</p>: identical to uname -r output. literally the same thing, no cap. ๐Ÿ”ฅ
  • "%V" โ€” Directory for larger and persistent temporary files</p>: this is either /var/tmp or the path "$TMPDIR", "$TEMP" or "$TMP" are set to. (again: the directory may be specified without a trailing slash.) ๐ŸŒˆ
  • "%w" โ€” Operating system version ID</p>: the operating system version identifier of the running system, read from the VERSION_ID= field of /etc/os-release. If not set, resolves to an empty string. See os-release(5) for more. ๐ŸŽ€
  • "%W" โ€” Operating system variant ID</p>: the operating system variant identifier of the running system, read from the VARIANT_ID= field of /etc/os-release. If not set, it resolves to an empty string. os-release(5) for more information. โœจ

  • "%%" โ€” a single percent sign</p>, bestie ๐Ÿ’… just write "%%" anywhere you want one literal "%" to show up. that's it. that's the whole trick.

๐Ÿซถ IDEMPOTENCE

okay so real talk, this is the part that makes systemd-sysusers so chill to run: it will literally do nothing if the users or groups you asked for already exist, or if those users are already members of the groups you listed. ๐Ÿ’–

which means โ€” and this is the slay part โ€” normally there is no reason to override sysusers.d vendor configuration, except to block certain users or groups from being created. like, that's the only vibe-check-passing reason to go stomping on the vendor files. no cap. โœจ


๐ŸŒˆ SEE ALSO

go read those, bestie, they're the main characters here ๐Ÿ‘‘


๐ŸŽ€ NOTES

  1. User/Group Name Syntax โ€” https://systemd.io/USER_NAMES

that link is where the whole "what even counts as a valid user or group name" lore lives. check it if you're naming something cursed and need to know if the system will accept it ๐Ÿฆ‹


and that's a wrap on the whole page, my love ๐Ÿ’œ it's systemd 262.1 energy, it's SYSUSERS.D(5) in the section 5 lineup, and this edition is dated right there in the footer. go make some users. you're gonna eat. ๐Ÿ‘‘โœจ

๐Ÿ“ฆ where this page comes from
  • arch rolling: systemd 262.1-1 ยท LGPL-2.1-or-later AND CC0-1.0 AND GPL-2.0-or-later AND MIT-0
  • ๐Ÿ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms