$ adduser vs useradd - The Debian Trap
adduser vs useradd
On Debian and Ubuntu, two commands look like they do the same thing.
They do not.
adduser is a Perl script shipped by the adduser package. It
is a Debian-specific wrapper that applies sensible defaults: it
creates the home directory, copies the contents of /etc/skel,
adds the new user to the users group (or a private group, per
configuration), prompts interactively for a password, sets the
default shell from /etc/adduser.conf, and writes a couple of
helpful GECOS fields. The whole point of adduser is to be the
interactive command that gets a working user account in one
invocation.
useradd is a compiled binary shipped by the passwd package
(ironically named — it provides every user-management binary, not
just passwd). It comes from upstream shadow-utils and is the
same binary, with the same flags, on every Linux distribution that
ships shadow-utils. By itself, useradd <name> creates the
account in /etc/passwd and stops. No home directory, no skel
files copied, no password set, no group memberships beyond the
primary group. The user technically exists and can technically log
in if you give them a password, but nothing else has been done.
Verify the distinction on any Debian-derived system:
1$ file $(which adduser)
2/usr/sbin/adduser: Perl script text executable
3
4$ file $(which useradd)
5/usr/sbin/useradd: ELF 64-bit LSB executable, ...
The Portability Trap
The trap surfaces when scripts written on Debian are run on other
distributions. On RHEL, Fedora, CentOS, and Alpine, adduser is
either a symlink to useradd or a thin script with completely
different behavior. A Debian shell script that calls
adduser --disabled-password --gecos '' myservice will fail on
RHEL because RHEL's adduser does not understand
--disabled-password. The flag is specific to Debian's Perl
wrapper.
Ansible's user module hides this distinction behind a portable
interface that calls useradd directly. Hand-written shell that
calls adduser does not.
The Practical Rule
For interactive system administration on Debian, use adduser.
The defaults are correct, the prompts are useful, and you get a
working user account in one command.
For scripts, automation, configuration management, and anything
that should work on more than one distribution, use useradd with
explicit flags:
1useradd --create-home --shell /bin/bash --comment "My Service" myservice
Every flag is documented identically across distributions because
the binary is the same upstream code everywhere. The result on
Debian, RHEL, and Alpine is the same account with the same
attributes.
The same distinction applies to addgroup (Debian Perl wrapper)
versus groupadd (raw binary), deluser versus userdel, and
delgroup versus groupdel. In each pair, the wrapper is
Debian-specific and the raw binary is portable.
If your script needs to run on more than one distribution, use
the raw binary. If you are typing at a shell on a Debian box, use
the wrapper. Knowing which is which prevents the cross-distribution
surprise that catches operators porting their scripts for the
first time.