装好Ubuntu 22.04之后,很多人做的第一件事就是打开终端敲一句su root,然后被一句su: 认证失败结结实实挡在门外。如果你是从CentOS或者其他发行版切过来的,大概率还会反问一句:root怎么还不能登录?这不是密码输错了,也不是系统坏了,而是Ubuntu默认把root账号锁在shadow文件里。这篇文章就是来解决这件事的:怎么把root账户正确地启用、怎么让它在图形界面和SSH里都能登录、登录之后环境变量有哪些暗坑、以及我从实际排障中总结的几条排查链路,最后再聊聊开启root之后的安全收尾。全程按Ubuntu 20.04/22.04来写,其他版本大同小异,照着走基本不会翻车。
1. Ubuntu默认不让你直接登录root:挡在门外的是设计而不是bug
1.1 shadow文件里的那把锁
刚装完的Ubuntu,root账号其实是存在的,UID就是0,系统里所有root该有的文件、目录、权限都在,缺的只是登录凭证。你去看/etc/shadow里root那一行,第二个字段不是一串哈希,而是一个*或者!:
bash复制sudo grep '^root:' /etc/shadow | cut -d: -f1-2
输出类似:
code复制root:*:19080:0:99999:7:::
这个*的含义是:密码认证被禁用,任何密码都不可能对上。所以PAM在认证阶段直接返回失败,表现到终端上就是一句认证失败。这是Ubuntu从12.10版本开始搞的默认策略——安装系统时根本不让你设置root密码,只创建一个带sudo权限的普通用户。root账户不是被删了,而是被锁了,钥匙被藏起来了。
判断一个root到底处于什么状态,最直接的办法是用passwd -S查看:
bash复制sudo passwd -S root
root L 01/01/2020 0 99999 7 -1
L:locked,锁着。P:可用密码。NP:没有密码。
这个命令在后面的排查中很关键,建议先记住。
1.2 sudo模式的三重价值
很多从CentOS转过来的老手会觉得Ubuntu这套很别扭,明明我是管理员,非要每次sudo,还要输密码,麻烦不麻烦?但你冷静下来想,Ubuntu做这个设计的理由其实相当扎实:
- 减少攻击面。没有密码哈希的root,等于根本没有可被暴力破解的入口。远程扫描工具对着ssh端口扫一万次,也猜不中一个不存在的密码串。
- 审计留痕。所有sudo操作都会写进
/var/log/auth.log,记录哪个用户、在哪个终端、执行了哪条命令。一旦系统被人动过手脚,这条链路能帮你追到源头。root直连登录的话,审计颗粒度就粗得多。 - 多一步深思熟虑。输密码这件事看着烦,实际上是在给你一个“别干蠢事”的缓冲期。手放在回车键上的那一瞬间,人会本能地再扫一眼命令。这个心理机制,比任何alias都管用。
1.3 为什么CentOS习惯在Ubuntu上失灵
CentOS安装时直接让你设root密码,装完就能用root登录,连图形界面都可以直接登。Ubuntu走的路线完全不同:第一个创建的用户默认在sudo组里,日常管理全靠这个普通账号。两种设计没有绝对的对错,但习惯了“root就是管理员”的思维定势,到了Ubuntu上确实会不适应。
我自己刚到Ubuntu的头几天,也被这套机制折腾过:明明在CentOS上用得好好的ifconfig、iptables,到了Ubuntu上普通用户根本敲不出来,非得sudo。后来才明白,不是命令丢了,是普通用户的PATH里压根没有/sbin和/usr/sbin。这个问题在第4节里会更详细展开。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 手工开启root账号:passwd、usermod与“鉴定令牌操作错误”
2.1 动手之前先看锁定状态
启用root之前,先别急着敲命令,花十秒看一下当前状态。除了passwd -S root,还可以看shadow文件的锁定标志。Ubuntu的root锁有两种来源:一种是安装时的“无密码”状态(字段为*),一种是管理员后续用passwd -l或usermod -L主动锁的(字段为!)。这两种的处理方式不太一样:
*:从未设置过密码,直接sudo passwd root即可解锁并设密码。!:曾经有密码但被锁了,同样可以用sudo passwd root解锁,也可以先用usermod -U root解锁再单独设密码。
所以最干净的做法,其实就一条命令:sudo passwd root。它会同时把锁解开、把密码写进去。
2.2 两条开启路径与适用场景
我把实际用过、也推荐给别人的两条路径列一下:
路径A:标准交互式设置
bash复制sudo passwd root
系统会先要求你输入当前用户的sudo密码,然后让你输入新root密码并确认。输完后passwd -S root会从L变成P,到这一步,本地终端里su -切换root就已经可以用了。
路径B:脚本化设置(非交互)
某些场景下一行命令更合适,比如在自动化脚本里初始化环境:
bash复制echo 'root:你的新密码' | sudo chpasswd
注意,这种方式会把密码明文暴露在shell历史或者进程列表里,用在一次性初始化脚本可以,平时不推荐。另外Ubuntu 22.04默认的sudo配置里有tty_tickets机制,普通用户执行sudo时要求关联一个终端,所以脚本里如果没有tty,可能还需要加-S配合管道输入密码,这一点容易踩,提醒一下。
2.3 鉴定令牌操作错误的真实原因和修复
热词列表里有一个高频报错:“设置root密码时su:鉴定令牌操作错误”。这个英文原文是Authentication token manipulation error,它和我们平时看到的su: 认证失败(Authentication failure)不是一回事。认证失败是密码本身不对,令牌操作错误则是PAM在“写”密码的过程中失败了——也就是说,密码没写进去。
我在实际排障中遇到这个报错,九成是下面三种情况:
- 文件系统只读。最常见,尤其在做系统救援时。你从recovery mode或者GRUB单用户模式进去,文件系统还挂在ro状态,这时候
passwd往里写shadow必然失败。先执行mount -o remount,rw /再设密码。 - shadow被加了不可变属性。可能是安全加固时有人执行过
chattr +i /etc/shadow。用lsattr /etc/shadow看一眼,如果输出里有i,先用chattr -i /etc/shadow去掉,再操作。 - PAM配置被改过。比如
/etc/pam.d/common-password里加了奇怪的约束模块,导致写令牌时校验失败。
排查顺序建议是:
bash复制# 1. 看文件系统状态
mount | grep ' / '
# 2. 看不可变属性
lsattr /etc/shadow /etc/passwd
# 3. 看最近认证日志
sudo tail -20 /var/log/auth.log | grep -i passwd
把这三步跑完,报错的根因基本就浮出水面了。
3. 让root真正“登得进去”:图形界面与SSH双通道配置
3.1 GDM图形登录:注释掉那条“不希望root登录”的PAM规则
root密码设好之后,打开终端su -能进了,但如果你打开图形登录界面,输入root密码,大概率会看到屏幕一闪又回到登录界面——根因在GDM的PAM配置。
Ubuntu 22.04使用GDM作为显示管理器,登录认证走的是/etc/pam.d/gdm-password这个服务。里面有一行:
code复制# Ubuntu does not want root to login graphically
auth required pam_succeed_if.so user != root quiet_success
它的意思是:如果当前用户不是root,认证继续走;如果用户是root,auth阶段直接失败。这一行就是冲着root来的。要让root能图形登录,把这行注释掉:
bash复制sudo sed -i 's/^auth required pam_succeed_if.so user != root quiet_success/#auth required pam_succeed_if.so user != root quiet_success/' /etc/pam.d/gdm-password
改完重启GDM或直接重启系统:
bash复制sudo systemctl restart gdm3
如果你还需要root自动登录(我非常不建议,但确实有人这么干),/etc/pam.d/gdm-autologin里也有类似的一行,同样注释掉才能生效。
需要注意,PAM的规则是按文件加载顺序执行的,注释错行或者多注释了别的规则,可能导致普通用户也登录不了图形界面。改之前先sudo cp /etc/pam.d/gdm-password /root/gdm-password.bak留个备份,出问题能立刻还原。
3.2 SSH远程登录:PermitRootLogin与drop-in配置的优先级秘密
服务器场景更关心的是SSH能不能直接root登录。Ubuntu默认的/etc/ssh/sshd_config里,PermitRootLogin的默认值是prohibit-password。这个值的含义是:root只能用公钥登录,禁止用密码登录。所以即使你设好了root密码,远程用密码登录root照样被拒。
这里有个Ubuntu 22.04特有的坑:/etc/ssh/sshd_config文件顶部有一条Include /etc/ssh/sshd_config.d/*.conf,系统里所有的配置碎片都放在这个目录。OpenSSH读取配置时,涉及同一个选项,先读到的值生效,后读到的会被忽略。云镜像、预装脚本常常会在/etc/ssh/sshd_config.d/丢一个配置文件进去,比如Ubuntu云镜像里的60-cloudimg-settings.conf,里面就写了PasswordAuthentication yes。如果你直接往主配置文件里改PermitRootLogin yes,有可能被目录里先加载的配置覆盖,也可能反过来,容易让人困惑。
最稳妥的做法是自己在drop-in目录里新建一个配置文件,确保加载顺序靠后、覆盖意图明确:
bash复制sudo tee /etc/ssh/sshd_config.d/60-root-login.conf <<'EOF'
PermitRootLogin yes
EOF
改完先检查配置语法,再重启服务:
bash复制sudo sshd -t
sudo systemctl restart ssh
如果你用的是Ubuntu云镜像,建议顺便看一眼/etc/ssh/sshd_config.d/60-cloudimg-settings.conf的内容,别让那里面的配置和你自己写的打架。
3.3 配置生效验证:别用眼睛确认,让服务自己回答
很多教程到这里就让你“重启试试”,但重启是个黑盒,失败了你还是不知道哪一步出了问题。我习惯用sshd自带的提权模式直接问它当前生效的配置:
bash复制sudo sshd -T | grep -i permitrootlogin
输出permitrootlogin yes,说明SSH层面已经放开。再看PAM层面:
bash复制sudo grep -rn 'pam_succeed_if.so user != root' /etc/pam.d/
如果gdm-password和gdm-autologin里都注释干净了,图形登录基本就没问题了。本地终端登录可以通过按Ctrl+Alt+F3切到纯文本终端,用root账号直接登录验证——这一步能帮你把“系统层面”和“图形界面层面”的问题隔离开:文本终端能登,说明密码和账户没问题,问题只出在GDM/PAM环节。
4. 登录成功只是开始:PATH、shell加载顺序与防误操作环境
4.1 root的PATH问题:“找不到命令”不是没装
设好密码、成功登录root,别高兴太早。很多人在su到root之后,敲systemctl、ufw、sysctl这类命令会得到command not found。第一反应是“命令没装”,实际上多半是PATH不对。
Ubuntu的/etc/login.defs里定义了两套默认PATH:
ENV_PATH:普通用户,仅/usr/local/bin:/usr/bin:/binENV_SUPATH:root,完整路径/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
问题出在获取PATH的方式上。su不带-时只会切换用户,不会重新加载登录环境,PATH还是当前用户的;su -和sudo -i才会重新走登录流程加载完整PATH。所以同一个root,不同方式进去,看到的命令范围完全不同。
解决办法是在root的~/.bashrc里加一段兜底逻辑:
bash复制if ! echo "$PATH" | tr ':' '\n' | grep -q '/usr/sbin'; then
export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$PATH"
fi
这样无论怎么进入root,只要PATH里缺了sbin目录就自动补齐,不会重复追加。
4.2 login shell与non-login shell:同样一个root不同命运
很多人分不清su、su -、sudo -i、sudo su之间的区别,其实核心是login shell和non-login shell的加载差异:
| 进入root的方式 | shell类型 | 加载的配置文件 | PATH来源 |
|---|---|---|---|
su |
non-login | ~/.bashrc |
继承原用户PATH |
su - |
login | /etc/profile、~/.profile、~/.bashrc |
/etc/login.defs的ENV_SUPATH |
sudo -i |
login | /etc/profile、~/.profile、~/.bashrc |
sudo重置后的login环境 |
sudo su |
non-login | ~/.bashrc |
继承sudo者的PATH |
sudo bash |
non-login | ~/.bashrc |
继承sudo者的PATH |
这里有个实际经验:Ubuntu默认的/root/.profile会source ~/.bashrc,所以只要在.bashrc里配了PATH、alias、函数,su -、sudo -i、SSH登录这些login场景都能吃到。但sudo su这种非login场景只读.bashrc,如果有些配置写在.profile里,就会莫名其妙“不生效”。我自己的习惯是:用户级配置能放.bashrc就不放.profile,省得在不同进入方式下行为不一致。
4.3 给root一个阻止你犯错的提示符和习惯
root的杀伤力大,很大程度上因为默认提示符和普通用户长得一样,敲rm -rf的时候手指快过脑子。建议至少给root换一个红色提示符,成本极低,收益极高:
bash复制echo "export PS1='\[\e[1;31m\]\u@\h:\w# \[\e[0m\]'" >> /root/.bashrc
再顺手做两件事:开启HISTCONTROL=ignorespace,让以空格开头的命令不进历史记录,防止密码泄露在~/.bash_history里;设置TMOUT=600,root闲置10分钟自动踢出终端,减少“挂着root去倒水,回来发现别人坐在你电脑前”的概率:
bash复制echo "export HISTCONTROL=ignorespace" >> /root/.bashrc
echo "export TMOUT=600" >> /root/.bashrc
source /root/.bashrc
还有一个容易被忽略的点:root的~/.bash_history是不区分终端的,多个SSH会话写同一个文件,互相覆盖是家常便饭。真在意审计的话,建议给每个会话独立历史,或者干脆把历史记录交给syslog这类集中式日志去管。
5. 从“登不上”到“登得上”:四类典型失败的真实排查链路
5.1 本地su失败:沿着一条命令看完整链路
拿最常见的报错su: 认证失败来说,如果密码确实没输错,那问题大概率出在账户状态,而不是密码本身。完整的排查链路我喜欢按这个顺序走:
bash复制# 第一环:账户状态
sudo passwd -S root
# 第二环:shadow文件的锁标志
sudo grep '^root:' /etc/shadow | cut -d: -f1-2
# 第三环:认证日志
sudo tail -30 /var/log/auth.log | grep -i su
auth.log里如果出现类似pam_unix(su:auth): authentication failure; ... user=root的记录,说明PAM确实走到了密码校验环节,且校验失败。此时再配合passwd -S root看是L还是P:是L就重新sudo passwd root;是P且密码确定没错,就要检查/etc/pam.d/su文件是否被改过,或者root是否被某些安全模块(比如pam_access、pam_listfile)给拦了。
还有一个容易忽略的小细节:su命令默认要求执行者知道目标用户的密码,但root用户执行su到任意用户不需要密码。如果你当前已是root,却报su认证失败,基本可以断定认证模块有问题,别在密码上纠结。
5.2 图形界面登录死循环:auth.log就是你的FBI报告
root在GDM登录界面输入密码后,屏幕一闪回到登录界面,这是典型的“登录死循环”。很多人的第一反应是“密码不对”,但实际原因是GDM的PAM规则没有真正放开。排查思路分两步:
第一步,确认PAM规则状态:
bash复制sudo grep -n 'pam_succeed_if' /etc/pam.d/gdm-password
如果还能搜到user != root这行且没被注释,那死循环就是它造成的。按3.1节的方法处理掉再重启。
第二步,看日志确认系统到底怎么拒绝的:
bash复制sudo tail -50 /var/log/auth.log | grep -i 'gdm'
如果日志里是user unknown,说明PAM在认证阶段就把root判为“不存在”——还是pam_succeed_if在起作用。如果是authentication failure,说明密码没对上,去检查root密码本身。
另外,/root/.profile里如果有一行mesg n 2>/dev/null || true之类的输出,在GDM登录时读取失败,也可能导致会话起不来。遇到这种情况,把root的.profile里涉及tty的命令后面统统加|| true,避免异常输出中断会话初始化。
5.3 SSH拒绝密码:sshd -T和drop-in文件的配合
远程登录root时Permission denied (publickey),原因大概率是PermitRootLogin的默认值prohibit-password。这个错误信息容易让人误以为“只允许公钥”,所以很多人的第一反应是去生成密钥,其实你只是想用密码登录而已。
排查链路:
bash复制# 1. 查看实际生效的配置
sudo sshd -T | grep -i permitrootlogin
# 2. 查看drop-in目录里有没有干扰项
ls -l /etc/ssh/sshd_config.d/
# 3. 查SSH认证日志
sudo tail -30 /var/log/auth.log | grep sshd
日志里如果是Failed password for root,说明密码在被校验但不对,或者服务端明确拒绝了密码认证方式;如果是Permission denied (publickey),说明服务端根本没给密码认证的机会,是PermitRootLogin配置的问题。按3.2节写drop-in文件解决。
5.4 忘记root密码:recovery mode与GRUB救援通道
热词里有个场景:“esxi虚拟机ubuntu忘记root密码ctrl+d输入不了”——这是在救援模式下按提示按Ctrl+D,结果一直循环。说清楚原理:系统进入emergency mode后,要么输入root密码继续,要么按Ctrl+D让它再试一次启动流程。如果root密码本身忘了,按Ctrl+D只会回到“要我输密码”的死循环。
正确的做法是从GRUB下手:
- 重启系统,在GRUB菜单界面按
e进入编辑模式。 - 找到
linux /boot/vmlinuz-...开头的那一行,在行尾追加systemd.unit=rescue.target(或者直接写single,老内核也认)。 - 按
Ctrl+X启动,进入root shell。 - 此时根文件系统大概率是只读的,先重新挂载:
bash复制mount -o remount,rw /
passwd root
- 输完密码,执行
exec /sbin/init继续正常启动。
如果你忘了普通用户的密码,同样的方法进救援模式,用passwd 用户名重置即可。Ubuntu的recovery mode菜单里有现成的“root Drop to root shell prompt”选项,能不用手写GRUB参数就别写,少一步出错的机会。
有一点必须说透:任何能碰到机器物理控制台或虚拟机控制台的人,都可以用这种方式重置root密码。所以这个救援通道既是救命稻草,也是安全隐患。真在乎物理安全性,就得配BIOS开机密码和全盘加密,不能裸奔。
另外顺带排掉一个干扰项:热词里的error 1045 (28000): Access denied for user 'root'@'localhost'是MySQL/MariaDB的账号报错,不是操作系统root登录失败,别在/etc/shadow里找答案,那是另一篇的坑。
6. 开启root之后的安全收尾:哪些事我强烈建议你做
6.1 root账号不是日常驾驶模式
root账号激活是一回事,日常怎么用是另一回事。我在Ubuntu上摸爬滚打这些年,最大的体会是:root是维修工具,不是驾驶模式。日常装软件、改配置、管服务,sudo完全够用,而且每次sudo的权限边界清晰:这条命令要root,我授权root,仅限这一次。真要是长时间泡在root里,误操作的概率会指数上升。
有个很直观的例子:普通用户跑rm -rf /home/user/Desktop/backup/,顶多删个目录;root跑rm -rf /home/user/Desktop/backup少打一个斜杠或者手滑打成rm -rf /,整台机器的命运就不由你控制了。sudo那张“每敲一次密码就多一次确认”的网,拦住的是这种瞬间的冲动。
6.2 必做四件事:口令强度、SSH密钥、fail2ban、审计
如果确实因为业务需要长期开启root登录,下面四件事我视作底线:
- 口令强度。别用
123456、root这种送人头的口令。生成一个像样的:
bash复制openssl rand -base64 12
拿到一串类似aB3#dE7@fR9*的东西,记到你自己的密码管理工具里。没人要求root密码必须背下来,机器要的是强度,不是顺口。
-
SSH远程管理优先用密钥。既然
prohibit-password本身就是“仅密钥”模式,那就把公钥放到/root/.ssh/authorized_keys里,保持默认配置别改成yes。这样root密码就算被爆破,也没法通过密码远程登录root。 -
部署fail2ban。这个纯粹是防爆破的:
bash复制sudo apt install fail2ban
默认配置就能监控sshd的认证失败次数,超过阈值自动封IP。Ubuntu上装完基本开箱即用,值得花十分钟配一下。
- 开启审计习惯。定期看这几样:
bash复制last -20
lastb -20
sudo grep 'Accepted' /var/log/auth.log | tail -20
last看成功登录,lastb看失败登录,auth.log里的Accepted记录能告诉你谁在什么时候成功进来了。发现问题后再结合sudo的COMMAND记录追根。
如果某天发现root确实不再需要了,随时可以锁回去,数据和文件都不受影响:
bash复制sudo passwd -l root
以后要恢复,再sudo passwd root即可,解铃还须系铃人,这个锁和钥匙的设计就是这么简单。
6.3 到底什么时候才值得开root
那是不是永远别开root?也不是。我实际遇到的开root合理场景,主要是这几类:
- 嵌入式开发板和交叉编译场景。很多开发工具链要求root来挂载设备、操作分区、修改内核模块参数,热词里“开发板挂载ubuntu”就是这种典型场景。
- 系统救援和磁盘操作。比如用户密码全部失效、修改GRUB参数、重建initramfs、批量操作LVM卷,这些场景下sudo反而碍手碍脚。
- 某些遗留软件和自研脚本,它们写死了要用root运行,改应用代码的成本远高于开root的成本。
开root之前想清楚一个问题:这个root是为了“做成某件事”,还是为了“图方便”。前者开完用完可以锁回去,后者就该按6.2的清单认真加固。
我从CentOS切到Ubuntu的头一周,也被这个root搞得人仰马翻。后来想明白一件事:不管锁root还是开root,目的都不是为难用户,而是让系统可维护、可审计、别被自己手滑搞坏。开启root不是终点,怎么用它、怎么管它,才是真正考验运维功力的地方。如果你是在服务器上折腾,我的建议永远是:宁可多绕一层sudo,也别让root裸奔在公网面前。
