SSH 连 VPS 时突然出现 WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!,并以 Host key verification failed 结束?这条警告表示:当前服务器出示的主机密钥与客户端以前保存的不一致。重装 VPS、换 IP、恢复快照后可能发生这种情况;DNS 指错机器或连接被劫持也可能造成相同现象。先核对服务器身份,再更新本地记录,不要直接关闭主机密钥检查。
| 你确认的情况 | 应该做什么 |
|---|---|
| 刚重装或重建 VPS,且能从服务商控制台核对新主机密钥指纹 | 备份 known_hosts,只移除该主机的旧记录,重新连接并核对指纹 |
| 域名或 IP 最近调整,可能连到另一台机器 | 核对域名解析、控制台实例 IP 与 SSH 配置;确认目标机器后再处理记录 |
| 没有任何预期变更,或控制台指纹与连接时显示的不一致 | 停止连接,保留警告与旧记录,检查 DNS、跳板机和服务商状态 |
主机密钥不是你的 SSH 登录私钥。 它用于让客户端识别“正在连接的是不是之前那台服务器”。删除本地 known_hosts 记录不会更改服务器的登录密钥,也不能证明新服务器可信。OpenSSH 对主机身份变化发出警告,正是为了阻止服务器冒充或中间人攻击;相关行为见 OpenSSH ssh 手册。
如果平时用的是 ssh dev-vps 这样的别名,先在本地电脑运行:
ssh -G dev-vps | grep -Ei '^(hostname|port|user|userknownhostsfile|hostkeyalias|proxyjump) '
重点看 hostname、port、hostkeyalias 和 proxyjump。HostName 可能是域名,也可能是 IP;自定义端口、跳板机和单独的 UserKnownHostsFile 都会影响你应该检查哪条记录。再对照 VPS 服务商控制台中的实例 IP;使用域名时,检查当前 DNS 解析是否仍指向预期实例。不要只凭“域名没变”就认定是同一台机器。
查看本地已有记录时,用 ssh-keygen -F,它也能查找哈希化的 known_hosts 条目:
ssh-keygen -F example.com
ssh-keygen -F 203.0.113.10
上面的域名和 IP 都只是占位符,请替换成自己的地址。如果 SSH 使用 2222 等非默认端口,查找和清理时应使用 [主机]:端口 形式:
ssh-keygen -F '[example.com]:2222'
警告里的 Offending ... key in ...known_hosts:17 指出一个可能冲突的位置,但直接手工删除第 17 行容易误删别的记录,也处理不了同一主机在多个位置或哈希条目中的情况。优先使用 OpenSSH 的 -F 和 -R 命令。它们的主机与自定义端口语法见 ssh-keygen 手册。
打开 VPS 服务商提供的 Web 控制台、VNC 或串口控制台,确认进入的是目标实例。这个入口不依赖当前出问题的 SSH 连接。在服务器控制台运行:
ssh-keygen -l -E sha256 -f /etc/ssh/ssh_host_ed25519_key.pub
输出中的 SHA256:... 就是这台机器当前 ED25519 主机公钥的指纹。把它与 SSH 警告或重新连接时显示的 ED25519 指纹逐字符对照。若客户端显示的是 ECDSA 或 RSA,必须比较同一种密钥类型,可分别查看 /etc/ssh/ssh_host_ecdsa_key.pub 或 /etc/ssh/ssh_host_rsa_key.pub;不要拿不同算法的指纹互相比较。服务器主机密钥文件的位置见 OpenSSH sshd 手册。
如果服务商控制台本身直接提供 SSH 指纹,也可以用它核对,但要确认该值对应当前实例、当前密钥类型。无法取得独立指纹时,不要把网络扫描得到的指纹当作独立证明。
例如下面的命令只能看目标端口当前返回了什么公钥,不能验证对方真实身份:
ssh-keyscan -T 5 -p 22 -t ed25519 example.com 2>/dev/null | ssh-keygen -l -E sha256 -f -
只有把扫描结果与控制台或其他可信渠道的指纹匹配后,它才有助于排查。OpenSSH 的 ssh-keyscan 手册明确说明,未经独立验证就把扫描结果写入信任库会暴露于中间人风险。
下面的命令都在本地电脑执行。先备份,方便核查或恢复:
cp -p ~/.ssh/known_hosts ~/.ssh/known_hosts.backup.$(date +%Y%m%d%H%M%S)
如果报“文件不存在”,说明当前账号没有默认 known_hosts 文件;先检查 ssh -G 输出中的 userknownhostsfile,以及警告里给出的文件路径,不要创建一个文件来掩盖真正的冲突位置。
默认 22 端口、按域名连接的例子:
ssh-keygen -R example.com
如果之前还曾按 IP 直接连接,且该 IP 已确认是同一台目标实例,再单独移除 IP 的旧条目:
ssh-keygen -R 203.0.113.10
自定义 2222 端口的例子:
ssh-keygen -R '[example.com]:2222'
如果 ssh -G 或警告指出使用自定义文件,则用 -f 指向那个文件,而不是盲目修改默认文件:
ssh-keygen -R example.com -f ~/.ssh/project_known_hosts
ssh-keygen -R 会移除该主机的匹配记录,包括哈希化记录;这比删除整个 ~/.ssh/known_hosts 更有针对性。清理前提仍然是:你已经从独立渠道确认了新指纹及主机变更原因。
以默认端口为例,重新连接:
ssh -o StrictHostKeyChecking=ask [email protected]
客户端提示新的主机指纹时,再与控制台得到的同类型指纹比较;完全一致才输入 yes。登录成功后,可再次用 ssh-keygen -F example.com 查看新记录。使用 SSH 别名、非默认端口或跳板机时,沿用平时真实使用的连接命令,不要为了绕过警告临时改成另一个未经核对的地址。
StrictHostKeyChecking=accept-new 只会自动接受全新主机的密钥,不会接受已变化的密钥;StrictHostKeyChecking=no 会放宽变化密钥的处理,不适合当作这里的修复办法。选项行为以 OpenSSH ssh_config 手册为准。
新系统通常会生成新的主机密钥,本地却保存着旧系统的公钥,所以 SSH 会报警。但“我记得重装过”只能解释变化,不能代替指纹核验。先在控制台确认实例与新指纹,再清理旧条目。
确认域名解析指向的 IP 与服务商控制台一致,并检查 SSH 配置中的 HostName、ProxyJump、HostKeyAlias。如果域名现在指向一台新 VPS,它的主机密钥不同是正常现象;但仍应先从独立渠道核对新机器。
这些工具底层通常调用 SSH 客户端。先用本地终端复现并完成上述指纹核对和指定条目清理,再重试工具。VS Code 连接参数与常见登录错误另见 VS Code Remote SSH 连接 VPS 教程;如果修复主机身份后转为 Permission denied (publickey),请看 SSH 密钥登录配置。
不要输入 yes,也不要禁用主机密钥检查。保留警告内容,核对服务商控制台的实例、IP、DNS 记录、跳板机和 SSH 配置;必要时联系服务商确认是否有实例迁移或主机密钥轮换。只有目标机器与指纹都能解释清楚,才继续登录。
- 记下 SSH 警告显示的主机、端口、密钥类型和指纹。
- 用
ssh -G、服务商控制台和 DNS 记录确认实际目标。 - 从控制台获取当前实例的同类型主机密钥指纹。
- 指纹一致且变化原因明确后,备份
known_hosts,用ssh-keygen -R清理指定主机。 - 重新连接时再核对一次指纹,确认后才登录。
记住顺序:核对身份 → 清理旧记录 → 重新连接。这能解决重装 VPS 后最常见的 SSH 主机密钥报错,同时保留 SSH 本来要提供的身份保护。
