1. 用户管理是Linux体系里绕不过去的一道门槛
很多刚接触Linux的朋友都有这种感觉:刚装好系统、敲了几个命令觉得挺新鲜,但一学到用户和权限就开始犯迷糊。这里新建一个用户、那里改个组、改完还动不动权限不足,明明自己是管理员却连个文件都写不进去。说实话,这个阶段确实最容易劝退人,但也是从“会敲命令”走向“理解系统”的关键一步。
用户管理之所以重要,不光是考试要考,而是它直接关系着你那台机器的安全边界和使用体验。Linux骨子里就是个多用户、多任务的操作系统,从诞生的第一天起,就假设会有很多人共用同一台机器、各干各的活、互不干扰。没有一套好用的用户和用户组体系,资源的隔离、文件的归属、进程的管控根本无从谈起。
我见过不少只懂Windows的朋友转到Linux之后,习惯性拿管理员账号到处跑、动不动就sudo,结果要么把系统搞崩,要么把别人目录下的文件给误删了。出现这些问题的根源,不是命令不熟,而是没有建立起“用户身份决定操作边界”这套思维。这篇内容就是围绕Linux用户和用户组的建立、修改、删除、权限配置来展开,目标很简单:让你学完之后,自己就能动手管好一台多用户Linux机器,知道每一步操作背后改的是什么文件、影响的是什么范围,遇到权限问题不再两眼一抹黑。
这一篇属于“Linux入门到精通”系列的第三关,重点放在第二章节“用户管理”上。我会从最基本的概念讲起,结合真实服务器上常用的操作习惯,把命令、参数、配置文件的对应关系全部拆开揉碎讲清楚。适合刚学完基础命令、正在往系统管理方向走的读者,也适合工作里偶尔要碰Linux、想把用户管理这块彻底补齐的朋友。
2. 先搞清楚Linux里的用户到底是个什么东西
2.1 用户在系统里不是“一个名字”,而是一串数字加一堆规则
在Windows里,用户的直观感受是那个登录界面上的头像和用户名。但在Linux底层,系统并不关心你叫什么,它认的是UID(User ID,用户ID)——一个纯数字标识。你在终端里看到的用户名,不过是系统为了方便人类记忆,把数字ID“翻译”成可读字符串而已。
这一点很重要,因为很多奇怪的问题都出在这里。比如你把某个用户的用户名改了,如果没处理好UID,文件的所有权看起来还是旧名字,甚至会出现两个名字指向同一个UID的情况。后面我会专门讲改名操作,这里先记住:Linux真正追踪身份靠的是数字ID,不是名字。
同样的,用户组也有自己的ID,叫GID(Group ID,组ID)。每个用户至少属于一个主组,这个主组就是用户创建文件时默认归属的组;此外还可以加入若干附加组,用来额外获取某些目录的访问权限。理解“主组”和“附加组”的区别,是后面玩转用户组管理的前提。
2.2 三种用户:超级用户、系统用户、普通用户
Linux里的用户大致分三类,理解了它们的定位,许多权限问题就不难猜出原因了:
- 超级用户(root):UID固定为0,拥有系统一切权限,可以无视绝大多数文件权限限制。它相当于整个系统的“总开关”,日常使用不建议直接拿它干活,更不建议拿它跑服务。
- 系统用户(伪用户):UID通常在1-999之间(不同发行版划分略有差异),是给系统服务、守护进程使用的账户,比如nginx、mysql、sshd等。这类用户一般没有家目录,也不能正常登录。
- 普通用户:UID从1000或500开始,是管理员手动创建、给真实人员使用的账户。这类用户有独立家目录,只能操作自己权限范围内的东西。
你可能会问:为啥要弄这些系统用户?很简单,服务程序如果带着root权限运行,一旦有漏洞被利用,攻击者直接就拿到管理员权限了,后果不堪设想。用最低权限的专用账户跑服务,这叫纪律,也是安全默认姿态。
2.3 用户信息藏在哪:四个核心配置文件要装在心里
管理用户,表面上是敲命令,实际上改的是下面这几个文本文件。任何时候你对用户操作结果有疑问,直接去翻这些文件,立刻就能看到系统的真实状态:
| 文件 | 作用 | 对应命令 |
|---|---|---|
| /etc/passwd | 存放用户基本信息:用户名、密码占位、UID、GID、备注、家目录、登录Shell | useradd/usermod |
| /etc/shadow | 存放用户密码的加密信息和密码时效策略 | passwd/chage |
| /etc/group | 存放用户组信息:组名、GID、组成员列表 | groupadd/groupmod |
| /etc/gshadow | 存放用户组的密码和管理员信息,日常很少直接动 | gpasswd |
这里特别提醒一句:/etc/passwd里那个写着“x”的位置并不是密码本身,只是占位符,真正的密码在/etc/shadow里,而且只有root能读。老版本Linux把密码直接放进/etc/passwd,任何人能读就意味着密码哈希可能被拿走暴力破解,后来才把密码挪到shadow里。这个设计思路到现在依然是安全基线,值得体会一下。
3. 创建用户:从useradd的基本操作到参数深挖
3.1 一个最简单的useradd加完之后发生了什么
创建用户的命令是useradd,最基础用法就是:
sudo useradd zhangsan不要以为敲完回车就完事了。这一条命令背后系统默默做了一堆事情:
- 读取/etc/login.defs和/etc/default/useradd这些默认配置文件,确定UID范围、默认Shell、家目录位置;
- 在/etc/passwd末尾追加一条记录;
- 在/etc/shadow里生成一条密码记录(此时密码字段通常是
!,意味着账户处于锁定状态); - 按规则分配一个可用UID;
- 创建以用户名命名的家目录(很多发行版默认还会复制/etc/skel里的骨架文件进去,这个目录里的.bashrc、.profile就是从这里来的)。
也就是说,如果你只是useradd zhangsan然后直接切换过去,会发现自己连密码都没有,根本登不进去。这也是新手最常见的坑:以为创建用户就完事了,忘了密码这步。正确的习惯是创建之后马上设置密码:
sudo passwd zhangsan它会交互式地让你输两次密码,写进/etc/shadow,这才算一个能用的账户。
3.2 实际抓生产服务器的关键参数
日常管理里,useradd往往不是裸奔使用的,得按需求加参数。我整理了最常用的一批:
# 创建用户并指定UID、主组、附加组、家目录、Shell,一次性配好 sudo useradd -u 1501 -g devgroup -G docker,extra -d /home/zhangsan -m -s /bin/bash zhangsan拆开来解释:
-u 1501:手动指定UID为1501,适合企业内部统一规划用户ID的场景;-g devgroup:设置主组,注意这里写的是组名或GID都行,但组必须已存在;-G docker,extra:设置附加组,多个组用逗号分隔,这是给用户追加“额外权限包”的主要方式;-d /home/zhangsan:指定家目录路径;-m:如果家目录不存在则自动创建,同时复制/etc/skel里的骨架文件;-s /bin/bash:指定登录Shell为bash。如果写/usr/sbin/nologin,就相当于告诉系统“这个账户不允许登录”,常用于跑服务的系统用户。
再补充两个管理上常用的:
-e 2026-12-31:设置账户过期日期,到期后用户无法登录,适合给临时工或实习生开账号;-f 7:密码过期后多少天内必须修改,否则锁定账户,这是账号安全策略里很实用的一招。
3.3 一个完整例子:给新同事开账号应该怎么做
假设公司运维收到需求:新同事张三明天入职,需要加入开发组,并且需要访问公司的日志分析工具目录。如果按照合格运维的流程,命令应该是:
# 1. 先看看组是否存在 grep devteam /etc/group # 2. 创建用户,指定主组和附加组 sudo useradd -g devteam -G logreader -d /home/zhangsan -m -s /bin/bash -c "Zhang San - Developer" zhangsan # 3. 设置初始密码,并强制首次登录改密码 sudo passwd zhangsan sudo chage -d 0 zhangsan这里chage -d 0的意思是“将密码最后修改日期设为0”,这样一来,用户第一次登录系统就会强行要求改密码。现实中给新员工开账号,这个操作几乎必做,避免初始密码一直不被修改。
3.4 验证用户是否创建成功
创建完之后,别急着走,用下面的命令对一遍:
# 查看用户基本信息 id zhangsan # 查看最近创建的账户 tail -3 /etc/passwd # 查看家目录结构 ls -la /home/zhangsanid命令输出里能看到UID、GID以及附加组列表,快速确认有没有配置错。这一步花不了十秒钟,却能在后期省掉很大麻烦。
4. 改密码和改用户:passwd、usermod、chage的组合玩法
4.1 passwd不只是改密码,还能锁用户
绝大多数人把passwd当成“改密码工具”,实际上它的权限远不止如此。
# 修改当前用户自己的密码 passwd # 修改指定用户的密码(只有root能做) sudo passwd zhangsan # 锁定指定用户的密码,禁止登录 sudo passwd -l zhangsan # 解锁指定用户的密码 sudo passwd -u zhangsan # 查看指定用户的密码状态 sudo passwd -S zhangsan-l参数锁定用户是通过在/etc/shadow密码字段前加“!”实现的,和解锁操作正好对应。如果你遇到有人离职但暂时不能删号的情况,最稳妥的做法是先把密码锁了,再把登录Shell改成nologin,双保险。只用一种,多少有些不保险。
4.2 usermod:用户信息的“后期编辑器”
用户创建之后几乎一定会遇到改需求的情况:张三换部门了、改名叫李四了、要加一个新权限组了。这时候用的就是usermod,它可以理解为useradd的孪生兄弟,语法和参数基本对应,只不过作用对象是已存在的用户。
常用场景举例:
# 把zhangsan的附加组更新为只保留docker和logreader sudo usermod -G docker,logreader zhangsan # 把zhangsan的主组改为ops sudo usermod -g ops zhangsan # 修改家目录,并确保旧家目录里的文件迁过去 sudo usermod -d /data/home/zhangsan -m zhangsan # 修改默认登录Shell sudo usermod -s /bin/zsh zhangsan # 修改用户备注信息 sudo usermod -c "Zhang San - Ops Engineer" zhangsan注意一个细节:-G参数如果不加-a,会覆盖原有附加组列表。很多新手第一次用usermod把用户加进docker组,结果发现用户原来所在的其他组全没了,一头雾水。正确做法是:
# 把用户追加到docker组,同时保留原有附加组 sudo usermod -aG docker zhangsan # 或者追加多个组 sudo usermod -aG docker,logreader zhangsan这个“追加”还是“覆盖”的区别,是我见过踩坑率极高的一处。记住一句话:给已有用户加组,默认加-a。
4.3 改名操作里的隐形坑:家目录和文件归属
usermod -l可以改用户名,但这里的水很深。比如:
sudo usermod -l zhangsan_new zhangsan改了名字之后,你会发现用户的家目录还是/home/zhangsan,如果直接改名不动家目录,系统提示该用户的home是旧路径,旧路径依旧叫旧名字,但家目录权限里的属主名显示仍为旧名字。如果没手动跟着改,就容易出现“用户换了名字,但是家目录里的文件Owner还是旧名字”的诡异现象。
正确姿势是名字和家目录一起改,旧家目录里的东西也得搬走:
sudo usermod -l zhangsan_new -d /home/zhangsan_new -m zhangsan-m负责把旧家目录内容迁移到新路径。如果漏掉这步,用户登录后很可能会得到一个空家目录,之前的配置文件啥的全不见了。
另外强烈建议,改名之前先确认这个用户没有正在运行的进程,不然可能出现进程所有者无法识别的异常状态。
4.4 chage:密码也是有时效的
很多公司对密码有时效要求,比如90天必须换一次,这种策略Linux同样支持,用的命令是chage。
# 查看密码时效信息 sudo chage -l zhangsan # 强制用户首次登录时修改密码 sudo chage -d 0 zhangsan # 设置密码最长使用90天,提醒提前7天,到期前3天强制修改 sudo chage -M 90 -W 7 -I 3 zhangsan参数含义分别是:
-M:密码最长使用天数;-W:密码过期前多少天开始提醒;-I:密码过期后多少天内必须修改,否则锁定账户。
实际管理里,如果公司安全制度要求定期改密,chage配合passwd就是最基础的自选动作组合。
5. 删用户与锁用户:善后工作比想象中麻烦
5.1 userdel和它容易忽略的遗留问题
删除用户的命令是userdel,但直接用userdel zhangsan只会删除/etc/passwd里的记录,家目录和mail spool文件都还在磁盘上。时间一长,服务器里会积累一堆没有归属者的“孤儿文件”。正确的删除姿势:
# 删除用户并同时删除家目录和邮件池 sudo userdel -r zhangsan-r这个参数会让系统把该用户的家目录以及/var/mail/zhangsan下的邮件文件一并清理掉。但我还是想提醒:删除是不可逆的操作,如果家目录里可能有需要留存的项目代码、备份脚本,请先打包备份再删,别图省事。
5.2 锁用户不等于删用户:最小改动原则
现实中更稳妥的处理策略往往是“先锁后用”,给后续追溯留有余地:
# 方法一:锁密码 sudo passwd -l zhangsan # 方法二:改登录Shell为nologin sudo usermod -s /usr/sbin/nologin zhangsan # 方法三:设置账户过期 sudo usermod -e 2020-01-01 zhangsan这三个方法各有侧重:锁密码最直接,但改了密码状态;改nologin能保留账户数据完整性,适合临时冻结;设置过期时间则适合“明确知道到期日”的场景。等确认这个人确实再也不需要这个账号了,再执行userdel -r也不迟。
5.3 如何找出系统里的“僵尸用户”
服务器托管久了,总会发现有些用户不知道是谁创建的,也从来没人登录。这时候可以用下面这条命令快速查看所有用户的最近登录时间:
sudo lastlog输出里会有每个用户最后一次登录的时间点,那些显示“Never logged in”的账户,基本可以判断为闲置账户。结合/etc/passwd排查一遍,如果确认无用,再走锁定和删除流程。这个排查习惯对一台多用户服务器来说很重要——你不主动清理,账户就会越积越乱,安全边界也会越来越模糊。
6. 用户组编辑:从一人一组的思维升级到团队协作
6.1 groupadd、groupmod、groupdel:组的生命周期管理
用户组的管理命令和用户高度对称:
# 创建用户组 sudo groupadd devteam # 指定GID创建组 sudo groupadd -g 2020 devteam # 修改组名 sudo groupmod -n devteam_new devteam # 修改GID sudo groupmod -g 2021 devteam # 删除用户组 sudo groupdel devteam删除组的时候有个限制:如果一个组是某个用户的主组,它是删不掉的,系统会报错“cannot remove the primary group of user”。这时候要么先把这个用户的主组改掉,要么先把用户删掉,然后再删除组。这是Linux给普通用户组设的“安全防护网”,防止你瞎删搞坏用户体系。
6.2 gpasswd:往组里加人/踢人,别再乱编辑文件
通过命令行管理组成员最稳妥的方式是gpasswd:
# 把用户加入某组 sudo gpasswd -a zhangsan devteam # 把用户移出某组 sudo gpasswd -d zhangsan devteam # 设置组管理员 sudo gpasswd -A zhangsan devteam组管理员可以在没有root权限的情况下管理组成员,适合那种“组长负责制”的团队:组长自己管理组员进出,运维不过度干预。
顺便提一句,不太建议手动编辑/etc/group文件来加删成员。文件格式本身不复杂,但并发操作时容易出现写坏、字段错位等问题。用命令操作,系统会处理好一致性。
6.3 为什么组用得好,sudo能少敲一半
用户组的价值往往通过权限继承来体现。最常见的场景就是:团队共享一个项目目录,希望组内成员都能读能写,其他人只能读。
我这里举一个经典例子。假设有个项目目录/data/project,需要让devteam组的所有成员都有读写权限:
# 把目录属组改成devteam sudo chown root:devteam /data/project # 把目录权限改成:属主读写,属组读写,其他人只可读 sudo chmod 0775 /data/project # 加上SGID位:新创建的文件自动继承目录的属组,保证团队协作时文件组归属一致 sudo chmod g+s /data/project这里chmod g+s加的是SGID位,它是一个非常实用但很多人忽略的设计。没有SGID时,新文件属组默认是创建者的主组;有了SGID,新文件自动归目录所属的组。多人协作时少了这步,文件往往会因为组归属不一致而互相读不了。
另外一个和组直接相关的高频操作是sudo权限分配。传统做法是给单个用户加sudo权限,但管理一多就会失控。更好的做法是创建一个admin组,然后让所有有管理需求的人加入这个组:
# 编辑sudoers文件,推荐用visudo避免语法错误 sudo visudo # 在文件里加入这一行,表示admin组里的所有成员都可以执行sudo %admin ALL=(ALL:ALL) ALL这样一来,给新人开管理员权限的流程就简化为:
sudo usermod -aG admin zhangsan走人的时候把人移出admin组,管理员权限也就回收了。用组来管理权限,而不是零散地改sudoers里的单个用户,这种思路能让运维工作轻松很多。
6.4 组的“主组”和“附加组”在权限计算时是怎么工作的
一个常见困惑是:用户同时在很多组里,那文件权限到底按哪个算?答案是这样的——判断一个用户能否访问某个文件,系统会看这个文件属主、属组、其他人这三档权限。如果用户刚好是文件属主,就用属主那档权限;如果不是属主,但用户属于文件属组(主组或附加组都算),就用属组那档权限;如果都不挨着,就用其他人那档权限。
实际应用里,一个用户通常把主要工作放到主组里,通过附加组来获得“第二身份”的访问权。比如用户的主组是个人组,附加组是docker,那么这个用户既能正常管理个人文件,又能操作docker相关资源,互不干扰。
7. 别硬背命令:用配置文件反向理解用户体系
7.1 一行passwd记录里藏着多少信息
用一个具体例子展示/etc/passwd里一行的完整结构:
zhangsan:x:1501:2020:Zhang San - Developer:/home/zhangsan:/bin/bash这段文本用冒号分隔成7个字段,依次是:
| 字段 | 含义 | 示例 |
|---|---|---|
| 1 | 用户名 | zhangsan |
| 2 | 密码占位符(x表示密码在shadow) | x |
| 3 | UID | 1501 |
| 4 | GID | 2020 |
| 5 | 用户备注信息(GECOS) | Zhang San - Developer |
| 6 | 家目录 | /home/zhangsan |
| 7 | 登录Shell | /bin/bash |
反过来也能看出,为什么改用户名不能只改第1个字段——后面第6个字段的家目录路径如果不跟着调整,那这个用户登录进来依旧用的是旧家目录逻辑。配置文件之间的联动关系,靠死记命令会漏,理解结构就不会。
7.2 shadow里“!”的含义:密码锁定的本质
/etc/shadow每一行是9个字段,核心是密码哈希和时效设置。开头几个常见的特殊符号含义如下:
!或!!:密码锁定,即使有密码也登不进去;*:系统用户专用,表示“永远不能登录”;- 空:完全没有密码。
所以当你怀疑一个用户为什么登录失败时,查看shadow文件里有没有“!”就一目了然。这也是许多排查思路的根基——不是你密码错了,是被锁了。
7.3 用命令行手工模拟useradd的全部过程
为了加深理解,可以尝试“手工建用户”:不敲useradd,只靠手动编辑文件和创建目录来实现。虽然真实环境不推荐这么做,但做过一遍的人对用户体系的理解会上一个台阶。
# 1. 在passwd末尾加一行 echo "testuser:x:1600:1600:Test User:/home/testuser:/bin/bash" >> /etc/passwd # 2. 在shadow加一行(这里用!表示未设密码) echo "testuser:!:18000:0:99999:7:::" >> /etc/shadow # 3. 创建对应的组 echo "testuser:x:1600:" >> /etc/group # 4. 创建家目录并设置权限 mkdir /home/testuser chown testuser:testuser /home/testuser chmod 700 /home/testuser做完这四步,这个用户就能正常登录使用了(当然还没设密码)。等你手工操作成功,再回头看useradd帮你自动完成了多少步骤,就会对这套机制有更深的体感。这个练习虽然有点野路子,但对理解配置文件之间的关系非常有效。
8. 实际环境中用户管理最容易踩的坑
8.1 主组不存在就useradd,命令直接报错
useradd -g nonexistgroup zhangsan这种情况,系统就直接拒绝执行,提示组不存在。遇到这种错误,先查组是否存在,再创建用户:
# 查到组名或者看到空结果 getent group devteam # 不存在就先建组 sudo groupadd devteam sudo useradd -g devteam zhangsan养成“先组后用户”的顺序习惯,可以减少很多无效报错。
8.2 家目录权限不对,用户登录后一片空白
有些用户能登录,但登录后提示家目录不存在或者变量为空。少见但容易出现的情况是:你手动创建了家目录却忘了chown,导致家目录属主是root,用户自己反而进不去。标准的权限应该是这样:
sudo chown zhangsan:zhangsan /home/zhangsan sudo chmod 755 /home/zhangsan注意:家目录本身一般不建议开777,如果设置成777,其他用户也能往里面写东西,风险很大。用700或755才是常规姿势。
8.3 改用户Shell时把Shell设成了不存在的路径
有人用usermod -s /bin/fish结果系统里根本没装fish,用户一登录直接失败。改完Shell后,最好顺手验证一下:
# 确认Shell路径存在 ls -l /bin/fish # 然后查看登录Shell是否正常 echo $SHELL另外提一句,把用户Shell改成/bin/false或者/usr/sbin/nologin虽然能禁止登录,但如果有服务在跑、需要以这个用户身份执行任务,这种改动可能引发服务启动失败。改动之前先想清楚继承影响。
8.4 批量创建用户时,别忘了一致性
给团队一次性开多个用户,建议先规划一个映射表,把用户名、UID、主组、附加组、家目录都列清楚,再写循环脚本执行。一个粗糙但有效的脚本示例:
for name in zhangsan lisi wangwu; do sudo useradd -g devteam -G docker -m -s /bin/bash "$name" echo "初始密码123456" | sudo chpasswd sudo chage -d 0 "$name" donechpasswd可以从标准输入批量设置密码,比一个个交互式敲passwd高效得多。但注意,脚本化操作千万别在生产环境盲目执行,尤其别在循环里对存量用户反复执行,否则会把已有用户重置掉。
9. 补充:关于sys_user和各类特殊账户的边界
很多教材提到“系统用户”时一笔带过,但在日常管理里,你会在进程列表里看到一堆像www-data、_apt、nobody这样的名字。网上一些解释会提到“系统用户跑服务更安全”这个思路,我在这里也强调一遍:最小权限原则是Linux安全实践的基石。给服务开独立账户、不让它拿到shell、不授予sudo权限,这些做法能极大降低服务被攻破后的横向扩散风险。
碰到系统服务报“Permission denied”错误时,排查思路往往是:先确认这个服务是用什么用户在运行,再看目录属主属组是否匹配,最后看权限位。比如nginx用户无法读取网站目录里的文件,通常就是目录权限或者属主问题,用:
sudo -u www-data ls /var/www/html来模拟服务账号视角,总比反复猜来的快。
如果你对系统用户和服务的对应关系有兴趣,可以查看系统服务配置里的指定用户参数,对比服务日志,逐步建立自己的排查感觉。这一步不是一蹴而就,但长期运维的价值很高。
10. 从这关往后,权限怎么学才不白费
用户和用户组整明白了,Linux权限体系的基础就打了一半。接下来该学的无非是文件权限的三位八进制、ACL扩展权限、特殊权限位(setuid/setgid/sticky bit)、sudo策略细化这些东西。但我个人觉得,比命令更重要的是建立一条判断链路:遇到“没权限”,先问是谁在操作(用户身份),再问操作哪个对象(文件/目录),然后看这个对象的属主属组和权限位,最后才决定要不要调整身份或权限。
实际干运维这几年,我遇到最多的问题还真不是命令不会,而是“搞不清当前到底是以谁的身份在执行操作”。whoami、id、sudo -u这些命令用熟了,就能随时切换视角,排查速度会快上很多。
这篇到这儿,用户/用户组管理的核心内容基本闭环了。最后留个小作业:找一台测试虚拟机,开三个普通用户、建两个用户组,按下面的规则操作一遍——用户A主组在组X、附加组在组Y;用户B主组在组Z;再创建一个共享目录,让A和B共同读写,同时其他用户只能读。做完这一步,你会发现后面学权限的时候顺畅很多。Linux的东西就是这样,关关难过关关过,但每过关一关,你对系统的掌控感就会明显上一个大台阶。