OpenSSH 10.5 在 2026 年 8 月 11 日发布。那天我在整理一批旧服务器的升级窗口,最先遇到的是一个看起来很普通的提示:主机指纹发生变化。熟悉 SSH 的人都知道,指纹变化可能只是服务器重装,也可能是 DNS 指向变了,更不能排除链路中出现了不该出现的机器。这个提示本质上是在提醒你核对 SSH 主机密钥。
麻烦在于,很多连接工具把“点一下继续”放得太顺手。只要用户名、密码和端口都对,终端看起来就像已经恢复工作。SSH 真正要确认的是另一件事:你现在看到的这把主机密钥,是否确实属于你要访问的那台机器。升级之后,客户端更频繁地收到新版本和密钥提示,这个判断反而更值得单独拿出来做,也就是认真处理 SSH 指纹变化。
我通常把问题拆成两层:先确认网络和认证有没有成功,再确认主机身份有没有被正确记住。第一层解决“能不能进”,第二层决定“进的是否是对的地方”。下面的例子以一台需要维护的 api-01 为主线,命令都可以在测试主机上复现。
先把“连接成功”拆成两个结果
SSH 客户端建立连接时,会先完成 TCP 握手、密钥交换,再进行主机密钥校验和用户认证。密码正确,只能说明服务器接受了这个用户;它不能替代主机密钥校验。把这几个阶段混成一个“登录成功”,后面排错时就会不停重试密码,却忽略了真正的分叉点。
OpenSSH 10.5 的发布说明提到,项目因为收到更多安全报告,暂时缩短了发布间隔。对运维来说,这不意味着每次升级都会改变连接行为,而是提醒我们把“客户端版本”和“服务器身份记录”都纳入变更记录。升级前后都能连上,并不代表 known_hosts 里的记录已经符合当前拓扑。

我会先用详细日志看它停在哪一层,而不是直接加 StrictHostKeyChecking=no:
ssh -vvv deploy@api-01
如果日志显示主机密钥不匹配,先停在这里。临时绕过检查会让命令继续,但同时也让后续审计失去依据。只有在隔离测试环境里,我才会用一次性参数验证网络是否通,再立即恢复严格校验。
指纹变了,先问“谁改了服务器”
最常见的误区是把指纹变化直接等同于攻击。实际上,系统重装、云主机重建、负载均衡后端替换、主机名复用,都会让旧记录失效。问题不在于变化本身,而在于你能不能从变更单、云平台控制台或服务器管理员那里拿到新的指纹来源。
在客户端上,可以先查现有记录:
ssh-keygen -F api-01
ssh-keygen -F 10.20.4.17
如果主机名和地址分别有记录,先确认它们是否应该指向同一台机器。OpenSSH 的发布说明还提到,客户端会在接受新主机密钥时展示已经关联的其他主机名或地址。这个提示有助于发现“同一把密钥被多个别名引用”的情况,但它仍然只是线索,不是管理员对服务器归属的证明。
确认来源后,再删除旧条目,而不是手工编辑整份文件:
ssh-keygen -R api-01
ssh-keygen -R 10.20.4.17
随后重新连接,让新的指纹按正常流程写入。若服务器只是临时切换了地址,保留旧记录并标注变更原因也可以;关键是让记录和现实拓扑保持一致,而不是为了消除红字把所有历史都抹掉。
还有一个容易被忽略的细节:同一台服务可能同时通过短主机名、完整域名和固定 IP 访问。三种写法在 known_hosts 中不一定是同一条记录,尤其当文件启用了哈希主机名时,肉眼很难判断它们是否对应同一把钥匙。我会把访问入口先统一成一个别名,再逐一核对其他入口,而不是在三处分别点击接受。
如果服务器由负载均衡器承载,后端节点轮换也可能让同一个域名出现多把合法主机密钥。此时要确认的是部署方是否明确支持多主机密钥,以及客户端配置是否允许这种模型。不能因为“每一把都能登录”就把所有指纹都加入个人电脑,正式环境应有一份可追溯的主机密钥清单。
UpdateHostKeys 解决的是迁移,不是盲目信任
很多人听到 UpdateHostKeys 会以为客户端会自动“修好”所有指纹问题。实际情况更窄:OpenSSH 在满足若干保守条件时,才会根据已经信任的主机密钥,帮助客户端迁移到服务器提供的其他密钥。比如现有密钥来自用户自己的 known_hosts,没有通配符冲突,也没有启用某些会改变校验路径的选项。
这是一种平滑迁移机制,不是首次连接时替你确认服务器。第一次遇到陌生主机,仍然需要从可信渠道核对指纹;已经确认过的主机,在算法升级或密钥轮换时,才可能减少一次人工切换。
可以查看最终生效的客户端配置:
ssh -G api-01 | grep -iE 'updatehostkeys|userknownhostsfile|verifyhostkeydns'
输出只代表当前配置计算结果,不代表服务器一定支持对应能力。服务器端是否提供新密钥、客户端是否真的写入,还要结合连接日志和 known_hosts 的变更时间判断。把“配置打开了”写成“密钥已经更新”,是另一种常见误判。
在自动化任务里,我会把这一步变成显式检查,而不是让脚本第一次运行时交互接受:先用受控的 known_hosts 文件运行探测,再把文件作为流水线的输入保存。这样做的代价是初次维护需要有人确认指纹,收益是脚本不会在无人值守时把错误主机写入共享环境。对需要轮换密钥的服务,还应安排一个新旧密钥并存的窗口,让客户端有机会完成迁移。

旧算法报错时,不要先把算法开回去
升级后最容易出现的另一类提示,是客户端和服务器没有共同的主机密钥算法。老设备仍只提供 ssh-rsa,新客户端默认不再把它放在首选列表里。有人会把 HostKeyAlgorithms=+ssh-rsa 写进全局配置,先让所有服务器恢复连接;这会把一个局部兼容问题扩大成所有连接的长期策略。
我更倾向于把兼容参数限定在单个主机,并给它一个明确的退出日期:
Host legacy-router
HostName 192.0.2.20
User ops
HostKeyAlgorithms +ssh-rsa
PubkeyAcceptedAlgorithms +ssh-rsa
同时记录设备固件或 SSH 服务的升级计划。OpenSSH 官方建议,在确认服务器只支持弱算法后,应优先升级服务器,而不是把旧算法永久加入默认配置。这里的“临时能用”必须和“什么时候删掉”同时出现,否则迁移就会变成新的遗留配置。
如果旧设备无法立即升级,我会在连接名上直接标注兼容原因,例如 legacy-router-rsa,并把配置放到单独的 Host 块。这样其他主机仍然使用默认算法,后续扫描配置时也能迅速找到待处理对象。兼容项应该像临时施工围挡一样有边界、有负责人,而不是散落在全局配置里的永久例外。
图形化工具能省动作,但不能替你做归属判断
在多台服务器的日常维护里,我会把连接名、主机名、端口和认证方式放进连接中心,把指纹核对结果放进变更记录。像 Xterminal 这类支持 SSH 连接管理和多种认证方式的工具,可以把跳板、密钥路径和连接分组收在一起,减少复制粘贴时把测试主机当成生产主机的概率。
但界面里的“接受新指纹”仍然是一个安全决策。工具能展示提示、保存连接和打开会话,却不能知道你刚收到的指纹是否来自正确的管理员。遇到重装或地址迁移,我会先在独立终端取指纹,与云平台或工单上的值核对,再回到图形界面更新连接。这样做多一个动作,却把“操作便利”和“身份判断”分开了。

反例:为什么清空 known_hosts 反而更难排查
有一次测试环境反复报主机密钥冲突,最省事的做法是删掉整个 ~/.ssh/known_hosts。这样确实能让下一次连接重新询问,但也同时删掉了其他服务器的历史证据。等到真正的生产主机出现异常时,你已经没有旧指纹可以比对,只能重新向所有系统负责人确认。
更稳妥的做法是只处理目标条目,并把旧文件先留档:
cp ~/.ssh/known_hosts ~/.ssh/known_hosts.before-api-01
ssh-keygen -R api-01
如果问题来自别名、端口或哈希主机名,先用 ssh-keygen -F 找到准确条目,再决定是否删除。排错的目标是恢复可验证状态,不是让提示消失得越快越好。
同样的原则适用于容器和临时实例。容器销毁后重新创建,主机名可能没变,但主机密钥已经换了;如果团队把容器当成长期服务器使用,known_hosts 很快会积累一堆无法解释的旧记录。更适合的做法是为临时环境使用独立的别名和独立文件,生命周期结束时一起归档,避免和生产主机混在同一份信任库里。
我会在什么条件下继续连,什么条件下停
可以继续连接的情况,是变更来源明确、指纹由可信渠道确认、旧记录只在目标主机上失效,并且兼容参数被限制在单个主机。升级后的新密钥能够通过正常流程写入,日志也能解释为什么发生迁移,这时“能连上”和“值得信任”才重新重合。
需要停下来的情况同样具体:管理员说没有改过服务器,DNS 却指向了另一台机器;跳板和目标分别出现不同的指纹提示;或者有人要求把严格校验全局关闭。此时继续输入密码没有意义,应该回到网络路径、DNS 和服务器变更记录。
对于团队协作,我会把“指纹变化”写成一个有上下文的事件:发生时间、访问入口、旧指纹、新指纹、变更单号和确认人。这样下一位值班同事看到同样的提示时,可以判断这是已批准的轮换,还是一个全新的异常。工具里保存的连接配置解决的是重复输入问题,工单和密钥台账解决的才是信任问题。
回到开头那台 api-01,OpenSSH 10.5 带来的真正变化体现在安全修复和更快的发布节奏。我的选择标准很简单:先证明“这是谁”,再处理“我能不能登录”;能解释密钥为什么变化,再把连接恢复到日常工具里。只要这条顺序不被省略,升级提示就不会变成被习惯性点击掉的红灯。