15%

全场主机优惠15%

测试技能,享折扣

使用代码:

Skills
开始使用
09.10.2024

useradd vs adduser:技术差异、使用场景及何时使用各自命令

`useradd` 是一个低级二进制工具,几乎在每个 Linux 发行版上都可用,它通过直接写入 `/etc/passwd`、`/etc/shadow` 和 `/etc/group` 来创建用户账户。`adduser` 是一个更高级的封装脚本——在基于 Debian 的系统上通常用 Perl 编写——它在内部调用 `useradd`,同时自动完成主目录创建、框架文件填充、密码提示和 GECOS 字段收集。两者的实际区别不仅仅是操作便捷性:在自动化配置流水线中或在非 Debian 系统上选择错误的工具,可能会悄无声息地产生不完整的用户账户。

这两个命令最终都会在系统的认证数据库中注册用户,但它们在默认行为、交互性、可移植性和可脚本化方面存在显著差异。本指南涵盖了管理员做出明智决策所需了解的每一个技术区别。

useradd 的底层工作原理

`useradd` 是 shadow-utils 软件包的一部分(在较旧的发行版上有时称为 `passwd`)。调用时,它执行一系列原子操作:

  1. 读取 `/etc/login.defs` 以确定默认 UID 范围、密码老化策略以及是否默认创建主目录。
  2. 读取 `/etc/default/useradd` 以获取默认 shell、框架目录路径和组行为。
  3. 向 `/etc/passwd` 和 `/etc/shadow` 写入新条目。
  4. 如果显式传递了 `-m`,则可选地创建主目录并从 `/etc/skel` 复制文件。
  5. 如果在 `/etc/login.defs` 中将 `USERGROUPS_ENAB` 设置为 `yes`,则可选地创建与用户名匹配的私有组。

许多指南忽略了一个关键点:在基于 Red Hat 的发行版(RHEL、CentOS、Rocky Linux、AlmaLinux)上,`useradd` 默认创建主目录,因为 `/etc/login.defs` 设置了 `CREATE_HOME yes`。而在 Debian 和 Ubuntu 上则不会——除非修改 `/etc/default/useradd`,否则 `-m` 标志是必须的。当管理员在不同发行版系列之间迁移时,这种行为不对称性是常见的混淆来源。

关键标志及其行为

标志用途说明
———————-
`-m`创建主目录在 Debian/Ubuntu 上不更改配置时为必需
`-d /path`设置自定义主目录路径除非同时使用 `-m`,否则不会创建目录
`-s /bin/bash`设置登录 shell默认为 `/bin/sh` 或 `/etc/default/useradd` 中的值
`-u UID`分配特定 UID必须唯一;使用 `-o` 允许重复
`-g GID`设置主组组必须已存在
`-G group1,group2`添加附加组逗号分隔,不含空格
`-e YYYY-MM-DD`账户过期日期写入 `/etc/shadow` 第 8 字段
`-f days`密码非活动期密码过期后账户被锁定前的天数
`-r`创建系统账户`/etc/login.defs` 中 UID 低于 `SYS_UID_MAX`,默认不创建主目录
`-M`明确不创建主目录覆盖发行版默认设置
`-N`不创建用户私有组用户的主组变为默认组
`-k /path`指定替代框架目录覆盖 `/etc/skel`

包含完整选项的 useradd 实用示例

“`bash

useradd

-m

-d /srv/appuser

-s /bin/bash

-u 1500

-g developers

-G sudo,docker

-e 2025-12-31

-c "Application Service Account"

appuser

passwd appuser

“`

在调用 `passwd` 之前不会设置密码。在此之前,账户存在但处于锁定状态——shadow 条目包含 `!` 作为密码哈希,阻止通过密码认证登录。但是,基于 SSH 密钥的登录不受此状态影响。

adduser 的底层工作原理

在 Debian 和 Ubuntu 上,`adduser` 是一个位于 `/usr/sbin/adduser` 的 Perl 脚本。它从 `/etc/adduser.conf` 读取自己的配置——这是一个与 `/etc/login.defs` 不同的文件——然后根据该配置和用户输入,使用适当的标志调用 `useradd`。

该脚本执行 `useradd` 单独无法完成的额外步骤:

  • 交互式提示输入密码,并通过第二次输入进行确认。
  • 通过引导式提示收集 GECOS 字段(全名、房间号、工作电话、家庭电话、其他)。
  • 自动从 `/etc/skel` 复制框架文件,无需 `-m`。
  • 设置主目录的正确所有权和权限。
  • 可选地将用户添加到 `/etc/adduser.conf` 中定义的附加组。

基于 Red Hat 的系统上,`adduser` 通常是指向 `useradd` 的符号链接,这意味着它与低级二进制文件行为完全相同——没有交互式封装器。这是编写跨发行版脚本时最重要的可移植性问题。

adduser 配置文件:/etc/adduser.conf

`/etc/adduser.conf` 中影响行为的关键指令:

“`

DSHELL=/bin/bash # Default shell

DHOME=/home # Parent directory for home directories

GROUPHOMES=no # Whether to create group-named subdirectories

LETTERHOMES=no # Whether to use first-letter subdirectories

USERGROUPS=yes # Create a group with the same name as the user

USERS_GID=100 # Default GID if USERGROUPS=no

DIR_MODE=0755 # Permissions on new home directories

SETGID_HOME=no

QUOTAUSER=""

SKEL=/etc/skel

SKEL_IGNORE_REGEX="dpkg-(old|new|dist|tmp)"

“`

修改此文件可让您在 Debian/Ubuntu 服务器集群中标准化用户创建,而无需每次都传递标志。

adduser 实用示例

“`bash

adduser customuser

“`

交互式会话如下所示:

“`

Adding user 'customuser' …

Adding new group 'customuser' (1001) …

Adding new user 'customuser' (1001) with group 'customuser' …

Creating home directory '/home/customuser' …

Copying files from '/etc/skel' …

New password:

Retype new password:

passwd: password updated successfully

Changing the user information for customuser

Enter the new value, or press ENTER for the default

Full Name []: Jane Smith

Room Number []:

Work Phone []:

Home Phone []:

Other []:

Is the information correct? [Y/n] Y

“`

使用 `adduser` 以非交互方式将现有用户添加到组:

“`bash

adduser customuser sudo

“`

这是一个值得注意的特性:`adduser` 同时充当组成员管理工具,而 `useradd` 无法通过单个命令实现这一点。

并排比较

特性`useradd``adduser`
类型二进制文件(C 程序)脚本(Debian 上为 Perl,RHEL 上为符号链接)
交互性非交互式;所有选项通过标志传递默认交互式提示
主目录除非传递 `-m`,否则不创建(Debian)自动创建
密码设置需要单独的 `passwd` 命令创建时提示输入
GECOS 字段通过 `-c` 标志以单个字符串设置交互式逐字段收集
框架文件仅在使用 `-m` 标志时复制始终复制
配置文件`/etc/login.defs`、`/etc/default/useradd``/etc/adduser.conf`
跨发行版可用性所有 Linux 发行版仅 Debian/Ubuntu(作为封装脚本)
脚本适用性优秀——完全非交互式较差——需要 `–disabled-password` 和 `–gecos` 标志以避免提示
系统账户通过 `-r` 标志支持通过 `–system` 标志支持
组管理仅在创建时可在创建后将用户添加到现有组
精细度对每个参数完全控制有主观默认值,精细度较低

何时使用 useradd

自动化和基础设施即代码

`useradd` 是任何非交互式场景的正确选择:Ansible playbook、Terraform provisioner、Docker `RUN` 指令、cloud-init 脚本和 CI/CD 流水线。它产生确定性输出,无需 stdin 依赖。

“`bash

Ansible task equivalent

useradd -m -s /bin/bash -G sudo -c "Deploy User" deployuser

echo "deployuser:$(openssl passwd -6 'securepassword')" | chpasswd

“`

跨发行版可移植性

任何旨在同时在基于 Debian 和基于 RHEL 的系统上运行的 shell 脚本都必须使用 `useradd`。依赖 `adduser` 的行为将在 CentOS、Fedora、Rocky Linux 或 Alpine Linux 上产生静默失败或意外行为。

系统和服务账户

为守护进程创建锁定的、无登录 shell 的服务账户是 `useradd` 的专长:

“`bash

useradd -r -s /usr/sbin/nologin -d /var/lib/myservice -m myservice

“`

`-r` 标志分配低于系统账户阈值的 UID,向管理员表明这不是人类用户账户,并且是在服务隔离至关重要的 VPS 托管环境中应用程序部署的标准模式。

精确的 UID/GID 控制

在 NFS 环境、容器编排或跨多台服务器同步用户数据库时,一致的 UID 和 GID 是必须的。`useradd -u 1500 -g 1500` 保证了这一点;`adduser` 在没有大量配置的情况下无法提供同样的确定性控制。

何时使用 adduser

交互式服务器设置

手动配置新的独立服务器并添加最初几个人类用户账户时,`adduser` 可降低设置不完整的风险。引导式提示使忘记密码步骤几乎不可能发生。

具有标准默认值的 Debian/Ubuntu 环境

如果您的整个基础设施运行 Debian 或 Ubuntu,并且您正在创建标准主目录用户,`adduser` 以更少的标志更快地产生正确结果。

创建后的组管理

将现有用户添加到现有组的 `adduser username groupname` 语法比 `usermod -aG groupname username` 更简洁,尽管两者都有效。

培训初级管理员

`adduser` 的交互性使其成为更好的教学工具。它突出显示重要字段(密码、全名),并隐藏 UID 范围和框架目录的复杂性,直到管理员准备好学习它们。

关键边缘情况和陷阱

缺少主目录的陷阱

在 Debian/Ubuntu 上,不带 `-m` 运行 `useradd username` 会创建用户但不创建主目录。用户可以登录(一旦设置了密码),但 `$HOME` 将不存在,导致任何在首次登录时写入主目录的应用程序失败——包括 `.bash_history`、`.ssh/authorized_keys` 和许多应用程序配置目录。

“`bash

Verify home directory existence after creation

ls -la /home/newuser || echo "Home directory missing — run: mkhomedir_helper newuser"

“`

Shadow 文件锁定

两个命令在写入期间都会锁定 `/etc/shadow`。在同时创建数十个用户的高并发配置脚本中,这会导致竞争条件。批量创建用户时请使用队列或顺序执行。

容器化环境中的 UID 冲突

带 cPanel 的 VPS 或其他控制面板环境中部署应用程序时,控制面板本身管理 UID 分配。使用硬编码 UID 手动运行 `useradd` 可能与面板分配的 UID 冲突,导致多个账户出现权限错误。在手动指定 UID 之前,请始终检查 `getent passwd | awk -F: '{print $3}' | sort -n`。

用于脚本编写的 adduser –disabled-password

如果您必须在脚本中使用 `adduser`(例如,为了利用其 `/etc/adduser.conf` 默认值),请抑制交互式提示:

“`bash

adduser –disabled-password –gecos "Automated User,,," scriptuser

echo "scriptuser:$(openssl passwd -6 'password')" | chpasswd

“`

`–gecos` 标志接受与 GECOS 字段匹配的逗号分隔字符串,消除所有交互式提示。

PAM 和 NSS 集成

`useradd` 和 `adduser` 都不配置 PAM 模块或 LDAP、Active Directory 或其他集中式认证系统的 NSS(名称服务切换)条目。在与 `sssd` 或 `winbind` 集成的服务器上,使用任一命令创建本地用户可能会与目录服务账户冲突或被其取代。在加入域的系统上创建本地用户之前,请验证 `/etc/nsswitch.conf`。

框架文件自定义

两个命令默认都从 `/etc/skel` 复制。对于管理共享虚拟主机环境的团队,每个用户需要预配置的 `.bashrc`、`.vimrc` 或 SSH 配置,正确的方法是在运行任一命令之前填充 `/etc/skel`——而不是在账户创建后修改文件。

验证用户创建

无论使用哪个命令,都要验证结果:

“`bash

Check passwd entry

getent passwd newuser

Check shadow entry (requires root)

getent shadow newuser

Check group memberships

groups newuser

id newuser

Verify home directory and permissions

ls -la /home/newuser

Test login shell

su -s /bin/bash – newuser -c "echo login successful"

“`

修改和删除用户

`useradd` 和 `adduser` 只创建账户。创建后的管理使用不同的命令:

  • `usermod` — 修改现有用户属性(shell、组、主目录、过期时间)。
  • `userdel` / `deluser` — 删除账户。Debian 上的 `deluser –remove-home username` 还会删除主目录和邮件假脱机。
  • `passwd` — 设置或更改密码,锁定/解锁账户。
  • `chage` — 管理密码老化和过期策略。

“`bash

Lock an account without deleting it

usermod -L username

Unlock

usermod -U username

Force password change on next login

chage -d 0 username

“`

实用决策矩阵

使用此清单选择正确的命令:

  • 脚本是否在非 Debian 系统上运行或需要可移植?使用 `useradd`。
  • 这是否是自动化、非交互式环境(CI/CD、Ansible、Docker)?使用 `useradd`。
  • 您是否需要特定的 UID/GID 以保持 NFS 或容器一致性?使用 `useradd -u -g`。
  • 您是否在创建没有登录 shell 的系统/服务账户?使用 `useradd -r -s /usr/sbin/nologin`。
  • 您是否在 Debian/Ubuntu 上交互式创建标准人类用户账户?使用 `adduser`。
  • 您是否想用简洁的单行命令将现有用户添加到组?使用 `adduser username groupname`。
  • 您是否在编写文档或培训 Debian 上的初级员工?使用 `adduser`。
  • 您是否需要在大规模情况下以非交互方式自定义主目录位置、过期时间或 shell?使用带有显式标志的 `useradd`。

正确的用户账户管理是服务器安全的基础。无论您是管理单台 VPS 还是一批独立服务器,准确了解每个命令写入磁盘的内容——以及它留下未设置的内容——可以防止因账户配置不完整而导致的权限提升和认证失败。

常见问题

useradd 默认创建主目录吗?

这取决于发行版。在基于 Red Hat 的系统(RHEL、CentOS、Rocky Linux)上,`CREATE_HOME yes` 中的 `/etc/login.defs` 使 `useradd` 自动创建主目录。在 Debian 和 Ubuntu 上,除非显式传递 `-m` 标志,否则不会创建主目录。

adduser 在 CentOS 或 Rocky Linux 上可用吗?

在基于 RHEL 的发行版上,`adduser` 是指向 `useradd` 的符号链接,而不是 Debian/Ubuntu 上的交互式 Perl 封装器。在 CentOS 上运行 `adduser username` 与运行 `useradd username` 行为完全相同——没有提示,没有 Debian 风格默认值的自动主目录。

如何在脚本中以非交互方式使用 adduser?

传递 `–disabled-password` 跳过密码提示,传递 `–gecos ""` 跳过 GECOS 字段提示:`adduser –disabled-password –gecos "" username`。之后使用 `echo "username:password" | chpasswd` 或通过管道传入 `openssl passwd -6` 哈希来设置密码。

/etc/login.defs 和 /etc/adduser.conf 有什么区别?

`/etc/login.defs` 是由 `useradd`、`userdel` 和 `usermod` 读取的系统范围配置文件——它控制 UID/GID 范围、密码老化默认值和主目录创建行为。`/etc/adduser.conf` 仅由基于 Debian 系统上的 `adduser` 和 `deluser` Perl 脚本读取,控制更高级别的默认值,如默认 shell、主目录父路径和框架目录。

我可以在同一台 Debian 服务器上安全地混合使用 useradd 和 adduser 吗?

可以。两者最终都写入相同的 `/etc/passwd`、`/etc/shadow` 和 `/etc/group` 文件。在系统级别,使用任一命令创建的账户是无法区分的。唯一实际的顾虑是一致性:如果您的团队交互式使用 `adduser`,而自动化脚本不带 `-m` 使用 `useradd`,您可能最终会有一些用户缺少主目录。请在每个环境中标准化一种方法并记录下来。

15%

全场主机优惠15%

测试技能,享折扣

使用代码:

Skills
开始使用