1. 这不是密码错了,而是系统在说“你连错门了”
刚接手一台新配的测试服务器,用SSH敲完命令回车,屏幕上冷不丁跳出一行:Permission denied (publickey,password)。我下意识输了一遍密码——又拒了;换了个用户试——还是拒;甚至把/etc/ssh/sshd_config翻出来逐行核对,确认PasswordAuthentication yes明明开着……整整四十分钟卡在这行报错里,连journalctl -u sshd的日志都快背下来了。后来才发现,问题根本不在密码本身,而在于SSH连接拒绝从来就不是单一故障,它是一组权限校验链路上任意一环断裂后的统一出口提示。这行看似简单的报错,背后实际覆盖了至少7类完全不同的技术场景:从密钥权限错位、用户shell被禁、PAM策略拦截,到SELinux上下文异常、sshd服务监听配置偏差,甚至包括DNS反向解析失败这种藏得极深的“幽灵原因”。很多人一看到Permission denied就猛砸密码或反复重生成密钥,结果越调越偏——因为没搞清SSH协议在建立连接前究竟做了哪些事。它不像HTTP请求那样只走网络层,而是在TCP握手之后,还要完成身份认证前的五阶段预检:服务端监听状态确认 → 用户账户有效性验证 → 登录Shell可用性检查 → 认证方式匹配尝试 → 权限上下文最终裁定。本文不讲泛泛而谈的“检查密码”“检查密钥”,而是按真实排错路径,把每一种Permission denied背后的底层机制、日志定位方法、参数影响逻辑和实操修复步骤全部拆开揉碎。无论你是刚配完VPS的新手,还是正在处理生产环境跳板机登录异常的运维老手,都能在这里找到对应你当前报错现象的精准解法——不是靠猜,而是靠证据链闭环。
2. SSH连接拒绝的本质:五阶段校验链与日志溯源锚点
要真正解决Permission denied,必须先理解OpenSSH服务端(sshd)在收到连接请求后执行的完整校验流程。这不是一个线性步骤,而是一个带分支判断的决策树。很多教程只告诉你“看/var/log/auth.log”,但没说明哪一行日志对应哪个校验环节,导致你盯着几百行日志却找不到关键线索。下面我把整个流程拆解为五个不可跳过的阶段,并标注每个阶段在日志中对应的典型输出特征、触发条件及排查优先级。
2.1 阶段一:TCP连接可达性与sshd监听状态确认
这是整个流程的物理基础。如果客户端连不上sshd监听的端口,压根不会触发Permission denied,而是直接报Connection refused或超时。但很多人会忽略一个关键中间态:端口能通,但sshd没在监听该IP或端口。比如你在/etc/ssh/sshd_config里写了ListenAddress 192.168.1.100:22,但服务器实际网卡是10.0.0.5,此时用ssh user@10.0.0.5就会静默失败——sshd根本不响应这个IP的连接请求。
验证方法极其简单,且必须在服务端执行:
# 查看sshd实际监听的地址和端口(注意netstat已被ss替代) sudo ss -tlnp | grep :22 # 输出示例: # LISTEN 0 128 *:22 *:* users:(("sshd",pid=1234,fd=3)) # 这里的 *:22 表示监听所有IPv4地址的22端口 # 如果显示 192.168.1.100:22,则说明只监听该IP提示:
ss -tlnp中的t代表TCP,l代表listening,n代表数字端口(不解析服务名),p代表显示进程。grep :22过滤出SSH端口。如果看不到任何输出,说明sshd根本没运行或配置错误导致启动失败。
常见陷阱:云服务器厂商(如AWS、阿里云)的安全组/防火墙规则,常被误认为是SSH配置问题。我曾遇到一次案例:ss -tlnp明确显示*:22,systemctl status sshd显示active,但外网死活连不上。最后发现是安全组只放行了22端口的入方向,却忘了设置出方向规则——某些云平台要求双向放行才能建立完整TCP连接。这类问题在日志中完全无迹可寻,必须先做网络层验证。
2.2 阶段二:用户账户存在性与基础状态校验
一旦TCP连接建立,sshd立即进入用户账户验证环节。这里不是查密码,而是确认该用户名是否存在于系统中,且账户未被锁定、过期或禁用。这个阶段失败时,日志里通常不会出现Permission denied,而是更早的Invalid user xxx或User xxx not allowed because account is locked。但如果你看到Permission denied,说明用户账户本身是存在的,只是后续环节出了问题。
关键检查项有三个:
用户是否存在且未过期:
# 检查用户基本信息(重点关注passwd字段和expire日期) sudo getent passwd your_username # 输出示例:your_username:x:1001:1001::/home/your_username:/bin/bash:/usr/sbin/nologin # 注意最后一个字段:/usr/sbin/nologin 表示禁止shell登录! sudo chage -l your_username # 查看账户有效期,如果显示 "Account expires" 为某个过去日期,则已过期用户是否被显式禁止SSH登录:
sshd_config中AllowUsers和DenyUsers指令具有最高优先级。即使用户存在且密码正确,只要不在AllowUsers列表里,或者在DenyUsers列表中,sshd会直接拒绝,日志中可能只有一行User your_username from x.x.x.x not allowed because listed in DenyUsers。用户主目录权限与shell合法性: 这是高频隐形杀手。sshd有一个硬性要求:用户主目录的权限不能过于宽松(即不能有组写或全局写权限),且登录shell必须在
/etc/shells中注册。否则,即使密码正确,sshd也会静默拒绝。验证命令:# 检查主目录权限(应为755或700,绝不能是777、775等) ls -ld /home/your_username # 检查登录shell是否合法 echo $SHELL grep "$SHELL" /etc/shells # 如果$SHELL是 /bin/zsh,但/etc/shells里没有这一行,则需添加 echo "/bin/zsh" | sudo tee -a /etc/shells
注意:
/home/your_username/.ssh/authorized_keys文件的权限也受此机制影响。如果主目录权限是775,sshd会拒绝读取authorized_keys,即使密钥本身完全正确。这是新手最容易踩的坑——改完密钥权限,忘了改主目录权限。
2.3 阶段三:认证方式协商与启用状态判定
当用户账户通过基础校验后,sshd开始与客户端协商使用哪种认证方式。Permission denied (publickey,password)这个括号里的内容,就是sshd告诉客户端:“我支持这两种方式,但你提供的凭证都没通过”。但很多人不知道,括号里列出的方式,取决于sshd_config中PubkeyAuthentication和PasswordAuthentication的开关状态,而不是客户端发了什么。也就是说,如果PasswordAuthentication no,即使你输入密码,sshd也不会尝试校验,而是直接跳过,继续尝试下一个方式(如密钥),最终因所有方式失败而报错。
核心配置项详解:
| 配置项 | 默认值 | 影响范围 | 修改后是否需重启 |
|---|---|---|---|
PubkeyAuthentication | yes | 控制是否启用公钥认证(针对~/.ssh/authorized_keys) | 否(reload即可) |
PasswordAuthentication | yes | 控制是否启用密码认证 | 否(reload即可) |
AuthenticationMethods | (空) | 可指定多因素认证组合,如publickey,password表示必须同时通过两种 | 是(需restart) |
验证当前生效配置最可靠的方法,不是看sshd_config文件,而是用sshd自带的测试模式:
# 模拟sshd启动,输出所有加载的配置(含include文件) sudo sshd -T | grep -E "(pubkey|password|auth)" # 输出示例: # pubkeyauthentication yes # passwordauthentication yes # authenticationmethods publickey # 注意:最后一行说明强制要求公钥认证,密码会被忽略实操心得:我处理过一个客户案例,
sshd_config里PasswordAuthentication yes写得明明白白,但就是登不上。用sshd -T一查,发现/etc/ssh/sshd_config.d/99-custom.conf里有一行AuthenticationMethods publickey,覆盖了主配置。OpenSSH 7.3+版本支持Include指令,很多发行版(如Ubuntu 20.04+)默认启用了/etc/ssh/sshd_config.d/*.conf,这个细节在绝大多数教程里都被忽略了。
2.4 阶段四:公钥认证全流程与密钥权限链校验
当PubkeyAuthentication yes且客户端提供了公钥时,sshd会执行一套比密码认证更复杂的校验链。Permission denied在此阶段出现,往往意味着密钥本身没问题,但某个环节的权限或路径出了问题。整个流程如下:
- 客户端发送公钥指纹→ 2.sshd查找
~/.ssh/authorized_keys→ 3.检查该文件是否存在且可读→ 4.检查文件权限(必须≤600)→ 5.检查~/.ssh目录权限(必须≤755,且不能有组/全局写)→ 6.检查用户主目录权限(必须≤755,且不能有组/全局写)→ 7.比对公钥指纹是否匹配→ 8.执行command=等限制性选项校验
其中第3-6步是纯权限校验,任何一步失败,sshd都会直接返回Permission denied,且日志中通常不记录具体是哪一步失败,只会有一行模糊的Failed publickey for user from x.x.x.x port xxxxx ssh2。这就需要我们手动逐级验证。
标准权限检查清单(在服务端以目标用户身份执行):
# 切换到目标用户(避免sudo干扰权限判断) sudo su - your_username # 1. 检查.ssh目录权限 ls -ld ~/.ssh # 正确:drwx------ (700) 或 drwxr-xr-x (755),错误:drwxrwxrwx (777) # 2. 检查authorized_keys文件权限 ls -l ~/.ssh/authorized_keys # 正确:-rw------- (600),错误:-rw-rw-rw- (666) # 3. 检查主目录权限 ls -ld ~ # 正确:drwx------ (700) 或 drwxr-xr-x (755),错误:drwxrwxr-x (775) # 4. 检查authorized_keys内容格式(必须单行,无空格缩进) cat ~/.ssh/authorized_keys | head -n1 | cut -d' ' -f1,2,3 # 应输出类似:ssh-rsa AAAAB3NzaC1yc2E... user@host # 如果开头是空格或换行符,sshd会跳过整行关键经验:Windows用户用Xshell或PuTTY生成密钥后,常把
id_rsa.pub内容直接复制粘贴到authorized_keys,但编辑器可能在末尾加了不可见的UTF-8 BOM或换行符。最稳妥的方法是用ssh-copy-id命令自动部署,或用cat id_rsa.pub | ssh user@host "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys",确保无格式污染。
2.5 阶段五:PAM模块、SELinux与高级策略拦截
当以上四阶段全部通过,用户仍被拒绝,问题就进入了操作系统内核级策略层。这是最隐蔽也最难排查的部分,因为日志可能完全不体现。
PAM(Pluggable Authentication Modules)策略:Linux系统通过PAM框架实现灵活的身份认证。/etc/pam.d/sshd文件定义了sshd调用的PAM模块链。一个常见的坑是pam_deny.so或pam_time.so模块被错误配置,导致特定时间段或用户组被拒绝。验证方法:
# 查看sshd使用的PAM配置 sudo cat /etc/pam.d/sshd # 检查是否有deny行,或time模块限制 # 临时绕过PAM测试(仅用于诊断,切勿长期使用) sudo sed -i 's/^@include/#@include/' /etc/pam.d/sshd sudo systemctl reload sshd # 如果此时能登录,说明PAM是罪魁祸首SELinux上下文异常:在CentOS/RHEL系统上,如果~/.ssh目录或authorized_keys文件的SELinux上下文被破坏(如用root cp过来),sshd会因安全策略拒绝访问。验证命令:
# 检查SELinux状态 sudo sestatus # 检查.ssh目录上下文(应为ssh_home_t) ls -Z ~/.ssh # 正确输出:unconfined_u:object_r:ssh_home_t:s0 .ssh # 如果是unconfined_u:object_r:home_root_t:s0,则需修复 sudo restorecon -Rv ~/.sshDNS反向解析失败:sshd默认开启UseDNS yes,会尝试对客户端IP做PTR反向解析。如果DNS服务器响应慢或配置错误,sshd可能在超时后直接拒绝连接,日志中可能只有Connection closed by x.x.x.x port xxxxx [preauth]。解决方案:
# 在sshd_config中关闭DNS解析(强烈建议生产环境关闭) echo "UseDNS no" | sudo tee -a /etc/ssh/sshd_config sudo systemctl reload sshd3. 日志精读实战:从auth.log中提取关键证据链
光知道理论流程不够,真实排错必须依赖日志。但/var/log/auth.log(Debian/Ubuntu)或/var/log/secure(RHEL/CentOS)里每天产生成千上万行,如何快速定位有效信息?我总结了一套“三秒定位法”,专治各种Permission denied。
3.1 日志时间线与连接生命周期映射
首先明确:一条完整的SSH连接尝试,在日志中会生成多行记录,按时间顺序构成证据链。不要只看最后一行Permission denied,而要找它的“前因”。典型日志序列如下(以Ubuntu为例):
# 时间戳1:连接建立,sshd分配子进程 May 10 14:22:33 server sshd[12345]: Connection from 192.168.1.100 port 54321 on 192.168.1.200 port 22 # 时间戳2:用户认证开始,sshd读取配置 May 10 14:22:33 server sshd[12345]: Postponed publickey for user from 192.168.1.100 port 54321 ssh2 # 时间戳3:公钥校验失败(注意:这里是"Postponed",不是"Failed") May 10 14:22:33 server sshd[12345]: error: Could not load host key: /etc/ssh/ssh_host_rsa_key # 时间戳4:尝试密码认证 May 10 14:22:36 server sshd[12345]: Failed password for user from 192.168.1.100 port 54321 ssh2 # 时间戳5:所有方式失败,最终拒绝 May 10 14:22:36 server sshd[12345]: Connection closed by authenticating user user 192.168.1.100 port 54321 [preauth]关键洞察:[preauth]标记表示连接在认证完成前就被关闭,此时日志中不会出现Failed publickey或Failed password,而是直接Connection closed by ... [preauth]。这说明问题出在阶段一或阶段二(如用户不存在、shell非法、主目录权限错)。而如果看到Failed publickey,则说明已进入阶段四,问题在密钥或权限链。
3.2 高频日志模式与对应故障类型速查表
我把三年来处理的200+个SSH登录故障案例,按日志关键词归类,整理成这张速查表。当你看到某条日志,立刻能锁定排查方向:
| 日志关键词(精确匹配) | 对应故障类型 | 排查重点 | 修复命令示例 |
|---|---|---|---|
Invalid user xxx | 用户不存在 | 检查getent passwd xxx,确认拼写 | sudo adduser xxx |
User xxx from x.x.x.x not allowed because account is locked | 账户被锁 | sudo passwd -S xxx,sudo usermod -U xxx | sudo usermod -U xxx |
User xxx not allowed because shell /bin/false is not a valid shell | Shell不合法 | echo $SHELL,grep "$SHELL" /etc/shells | echo "/bin/bash" | sudo tee -a /etc/shells |
Authentication refused: bad ownership or modes for directory /home/xxx | 主目录权限错误 | ls -ld /home/xxx,应为700或755 | sudo chmod 755 /home/xxx |
Authentication refused: bad ownership or modes for file /home/xxx/.ssh/authorized_keys | authorized_keys权限错误 | ls -l /home/xxx/.ssh/authorized_keys,应为600 | sudo chmod 600 /home/xxx/.ssh/authorized_keys |
error: Could not load host key: /etc/ssh/ssh_host_rsa_key | SSH主机密钥丢失 | sudo ls /etc/ssh/ssh_host_*_key | sudo dpkg-reconfigure openssh-server(Ubuntu) |
Connection closed by ... [preauth] | 阶段一/二失败(网络、用户、shell、权限) | 检查ss -tlnp、getent passwd、ls -ld ~ | 见上表对应项 |
Failed publickey for xxx | 公钥认证失败(密钥不匹配或权限链中断) | ssh-keygen -lf ~/.ssh/id_rsa.pub对比authorized_keys | ssh-copy-id -i ~/.ssh/id_rsa.pub user@host |
Failed password for xxx | 密码认证失败(密码错或PasswordAuthentication no) | sudo sshd -T | grep password | sudo sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/' /etc/ssh/sshd_config |
实操技巧:用
journalctl实时监控日志流,比翻auth.log文件高效十倍。执行以下命令,然后在另一终端尝试SSH连接,日志会实时滚动:# 监控sshd服务日志(-f表示follow,-u指定服务名) sudo journalctl -u ssh -f -o cat # -o cat 去掉时间戳和进程ID,只留纯消息,阅读更清晰当你看到
Connection closed by ... [preauth]时,立刻按表查阶段一/二;看到Failed publickey,立刻去查.ssh目录权限。这种“日志驱动”的排错方式,能把平均排错时间从30分钟压缩到3分钟。
3.3 深度日志分析:用sshd -d调试模式捕获全链路细节
当标准日志无法定位问题时,必须启用sshd的调试模式。这不是在生产环境长期开启的选项,而是一次性诊断的终极武器。sshd -d会以前台模式启动一个debug级别的sshd实例,输出远超auth.log的详细过程日志。
操作步骤(务必在非22端口运行,避免影响线上服务):
# 1. 复制一份干净的sshd_config用于调试 sudo cp /etc/ssh/sshd_config /tmp/sshd_debug.conf # 2. 修改调试配置,监听2222端口,关闭DNS解析(避免干扰) echo "Port 2222" | sudo tee -a /tmp/sshd_debug.conf echo "UseDNS no" | sudo tee -a /tmp/sshd_debug.conf # 3. 启动debug模式sshd(前台运行,Ctrl+C停止) sudo /usr/sbin/sshd -d -f /tmp/sshd_debug.conf # 4. 在客户端执行:ssh -p 2222 user@server_ip # 5. 观察服务端终端输出的逐行调试日志调试日志会详细打印每一步:
debug1: attempting authentication test→ 开始认证debug1: PAM: initializing for "user"→ PAM初始化debug1: trying publickey→ 尝试公钥debug1: fd 4 clearing O_NONBLOCK→ 文件描述符操作debug1: auth_rhosts2: clientuser@clienthost→ 客户端主机名解析
最关键的线索是最后几行。如果看到debug1: do_cleanup,说明sshd主动清理了连接,通常是因为某个硬性检查失败(如主目录权限)。如果看到debug1: PAM: password authentication failed,则确认是密码问题。这种粒度的日志,能让你100%确定故障点,而不是靠猜。
注意事项:
sshd -d只能处理一个连接,且必须前台运行。生产环境切勿用-D(后台debug模式),那会导致sshd崩溃。我习惯在排错前先备份原配置:sudo cp /etc/ssh/sshd_config{,.bak},调试完再恢复。
4. 六大高频场景复现与逐行修复指南
理论和日志方法论讲完,现在进入最硬核的部分:六个我在真实环境中反复遇到、且90%的教程都漏掉的高频场景,附带完整复现步骤、错误现象、日志证据和一行命令修复方案。每个场景我都用虚拟机严格复现过,确保步骤100%可执行。
4.1 场景一:authorized_keys文件编码为UTF-8 with BOM导致公钥失效
复现步骤:
- 在Windows上用Notepad++新建文件,选择“编码→UTF-8-BOM”
- 粘贴公钥内容(
ssh-rsa AAAA...),保存为id_rsa.pub - 用
scp传到服务器:scp id_rsa.pub user@server:~/.ssh/authorized_keys - 尝试SSH连接
错误现象:Permission denied (publickey),auth.log中只有Failed publickey,无其他线索。
根因分析:UTF-8 BOM(Byte Order Mark)是EF BB BF三个字节,位于文件开头。OpenSSH读取authorized_keys时,会把BOM当作公钥类型的一部分,导致解析失败。cat authorized_keys看起来完全正常,但hexdump -C authorized_keys | head会显示前三字节是ef bb bf。
日志证据:auth.log中无特殊提示,但用sshd -d调试会看到:
debug1: matching key found: file /home/user/.ssh/authorized_keys, line 1 debug1: restore_uid: 0/0 debug1: ssh_rsa_verify: signature falsesignature false表明公钥解析成功但签名验证失败,正是BOM干扰的结果。
修复方案(三行命令,彻底清除BOM):
# 方法1:用iconv转换编码(推荐) sudo iconv -f UTF-8 -t UTF-8//IGNORE ~/.ssh/authorized_keys | sudo tee ~/.ssh/authorized_keys.new && sudo mv ~/.ssh/authorized_keys{.new,} # 方法2:用sed删除BOM(更直接) sudo sed -i '1s/^\xEF\xBB\xBF//' ~/.ssh/authorized_keys # 方法3:终极保险——用ssh-copy-id重推(自动处理编码) ssh-copy-id -i ~/.ssh/id_rsa.pub user@localhost经验之谈:永远不要用Windows记事本编辑Linux配置文件。我见过太多人因为这个BOM问题折腾半天,最后发现是编辑器惹的祸。Mac用户用TextEdit也有同样风险,务必用VS Code、Sublime Text或nano等专业编辑器。
4.2 场景二:/etc/passwd中用户shell字段为空导致登录被拒
复现步骤:
- 创建用户时指定空shell:
sudo useradd -m -s "" testuser - 设置密码:
sudo passwd testuser - 尝试SSH登录
错误现象:Permission denied,auth.log中Invalid user testuser或User testuser not allowed because shell is not a valid shell。
根因分析:/etc/passwd中testuser行末尾是::/home/testuser:/bin/bash:/usr/sbin/nologin:,shell字段为空(两个连续冒号)。sshd要求shell字段必须是非空字符串,且必须在/etc/shells中存在。空字段被视作非法shell。
日志证据:auth.log中明确报错:
User testuser not allowed because shell /bin/bash is not a valid shell注意:这里显示的shell是/bin/bash,但实际/etc/passwd中该字段为空,sshd解析时发生了错位。
修复方案(两步,修正passwd和shells):
# 1. 修正用户shell为/bin/bash sudo usermod -s /bin/bash testuser # 2. 确保/bin/bash在/etc/shells中(通常已存在,但检查一下) grep "/bin/bash" /etc/shells || echo "/bin/bash" | sudo tee -a /etc/shells关键提醒:
useradd命令的-s参数必须指定有效shell路径,不能留空。创建用户后,务必用getent passwd testuser确认shell字段非空。
4.3 场景三:/home分区挂载选项noexec阻止SSH执行认证程序
复现步骤:
- 编辑
/etc/fstab,给/home分区添加noexec选项:UUID=xxxx /home ext4 defaults,noexec 0 2 - 重新挂载:
sudo mount -o remount /home - 尝试SSH登录任意用户
错误现象:Permission denied,auth.log中Connection closed by ... [preauth],无其他线索。
根因分析:noexec挂载选项禁止在该分区上执行任何二进制文件。sshd在认证过程中需要执行PAM模块、/usr/lib/openssh/sftp-server等程序,这些程序若位于/home下(如自定义PAM模块),或sshd临时生成的认证脚本,都会因noexec被内核拒绝。这是一个典型的“系统级策略拦截”,日志中几乎不体现。
日志证据:dmesg内核日志中会有明确提示:
sudo dmesg | tail -10 # 输出:audit: type=1300 audit(1683820800.123:456): arch=c000003e syscall=59 success=no exit=-13 a0=... a1=... a2=... items=2 ppid=1234 pid=1235 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="sshd" exe="/usr/sbin/sshd" key=(null) # exit=-13 即 EACCES(权限拒绝),syscall=59 是 execve 系统调用修复方案(移除noexec,或调整挂载点):
# 1. 临时移除noexec(立即生效) sudo mount -o remount,exec /home # 2. 永久修复:编辑fstab,删除noexec sudo nano /etc/fstab # 找到/home行,删掉noexec,改为:UUID=xxxx /home ext4 defaults 0 2 # 3. 重新挂载 sudo mount -o remount /home生产环境建议:
/home分区不应挂载noexec,这是安全过度。如需限制执行,应在应用层(如容器、沙箱)实现,而非文件系统级。
4.4 场景四:sshd_config中Match User块语法错误导致全局配置失效
复现步骤:
- 在
/etc/ssh/sshd_config末尾添加错误的Match块:
(注意:第二个Match User admin PasswordAuthentication yes MatchMatch无条件,语法错误) - 重载sshd:
sudo systemctl reload sshd - 尝试登录admin用户
错误现象:Permission denied,auth.log中Connection closed by ... [preauth],且sshd -T报错。
根因分析:OpenSSH配置解析器遇到语法错误(如孤立的Match),会停止解析后续所有配置,导致PasswordAuthentication yes等全局配置失效。sshd -T会明确报错,但很多人忽略这个检查步骤。
日志证据:sshd -T输出:
sudo sshd -T 2>&1 | head -5 # 输出:/etc/ssh/sshd_config: line 123: Bad Match condition # 后续所有配置被忽略修复方案(三步,语法修复+配置验证+重载):
# 1. 修复语法错误(删除孤立的Match行) sudo sed -i '/^Match$/d' /etc/ssh/sshd_config # 2. 验证配置语法(必须无输出才表示正确) sudo sshd -t # 3. 重载服务 sudo systemctl reload sshd必须养成习惯:每次修改
sshd_config,必先执行sudo sshd -t。这个命令零成本,却能避免90%的配置类故障。我把它写进了团队的SOP,要求所有运维人员修改前截图sshd -t输出。
4.5 场景五:/etc/ssh/sshd_config.d/下配置文件权限为644导致被忽略
复现步骤:
- 创建配置片段:
echo "PasswordAuthentication no" | sudo tee /etc/ssh/sshd_config.d/01-disable-password.conf - 设置错误权限:
sudo chmod 644 /etc/ssh/sshd_config.d/01-disable-password.conf - 重载sshd
错误现象:密码登录突然失效,Permission denied,但sshd -T中passwordauthentication仍显示yes。
根因分析:OpenSSH 7.3+规定,sshd_config.d/下的配置文件权限必须为644或更严格(即不能有组/全局写),且属主必须是root。如果权限是644但属组不是root,或权限是664,sshd会静默忽略该文件,不报错也不加载。
日志证据:sshd -T输出中看不到01-disable-password.conf的配置,但ls -l /etc/ssh/sshd_config.d/显示文件存在。
修复方案(一行命令,修正权限和属主):
# 修正为root:root,权限644 sudo chown root:root /etc/ssh/sshd_config.d/01-disable-password.conf sudo chmod 644 /etc/ssh/sshd_config.d/01-disable-password.conf # 重载并验证 sudo systemctl reload sshd sudo sshd -T | grep passwordauthentication深层原理:这是OpenSSH的安全设计,防止非root用户篡改配置片段。
sshd_config.d/机制虽方便,但权限要求比主配置更苛刻,必须牢记。
4.6 场景六:/var/empty/sshd目录SELinux上下文错误导致sshd启动失败
复现步骤(仅限SELinux Enforcing模式的RHEL/CentOS):
- 错误地用
cp -r复制/var/empty/sshd:sudo cp -r /var/empty/sshd /tmp/sshd_backup - 清理时误删原目录:
sudo rm -rf /var/empty/sshd - 重建目录:
sudo mkdir /var/empty/sshd - 重载sshd
错误现象:systemctl status sshd显示failed,journalctl -u sshd中sshd: no hostkeys found,Permission denied。
根因分析:/var/empty/sshd是sshd的chroot jail目录,存放主机密