一、开场白:集群很乖,也有脾气
实验室里新装了两台 Proxmox VE(后面简称 PVE),取名 proxmox-a (192.168.2.7) 和 proxmox-b (192.168.2.8)。
把它们肩并肩加入同一个集群后,本以为可以左手右手一个慢动作——在任何一台的 8006 Web 面板里都能随意启停对方的容器。结果现实给我上了一课:
- 在 B 的 8006 里点 A 的容器 → 秒开秒关,乖巧听话。
- 在 A 的 8006 里点 B 的容器 → “嘭”弹红框,死活不给面子。
于是,一条诡异的“管理单行道”横空出世。
二、事故现场高清回放
1. Web 端症状
打开浏览器 F12 开发者工具抓取网络请求,能看到失败的 API 调用:
POST https://192.168.2.7:8006/api2/json/nodes/proxmox-b/lxc/101/status/start
服务器返回了 500 内部服务器错误,而响应的正文里嵌着熟悉的 SSH 报错字样。
2. 后台日志佐证
在 A 节点上查阅 /var/log/syslog,找到了关键线索:
pvedaemon[1234]: problem connecting to 'proxmox-b' - ssh: handshake failure
这说明 PVE 的后台守护进程 (pvedaemon 或其代理) 试图通过 SSH 连接到节点 B,但握手过程直接失败了。
3. 控制台手动复现
为了进一步确认,切换到 A 节点的命令行,手动执行 SSH 连接:
ssh root@192.168.2.8
屏幕瞬间被醒目的“大横幅”警告占满:
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the RSA key sent by the remote host is
SHA256:P4UMJmTShfmaJoxDCraoHRwIngNtjA5JIlL/hnsmr1Y.
Please contact your system administrator.
Add correct host key in /root/.ssh/known_hosts to get rid of this message.
Offending RSA key in /etc/ssh/ssh_known_hosts:12
remove with:
ssh-keygen -f “/etc/ssh/ssh_known_hosts” -R “192.168.2.7”
Host key for 192.168.2.7 has changed and you have requested strict checking.
Host key verification failed.
翻译成更直白的话就是:“对方(节点B)出示的 SSH 主机密钥指纹,和我(节点A)本地记录里保存的对不上号。出于安全考虑(担心是中间人攻击),我拒绝连接!”
三、架构速览:8006 面板背后的“暗线”通信
理解故障原因,需要先明白 PVE Web 管理面板 (https://IP:8006) 操作远程节点的底层逻辑。它并非浏览器直接与目标节点对话,而是遵循以下链条:
- 你的浏览器 → 向当前登录的节点(例如节点A)的 8006 端口发送请求。
- 节点A上的
pve-proxy 服务接收到请求 → 通过 SSH 协议连接到目标节点(例如节点B)的 22 端口。
- 节点B的
sshd (SSH服务) 将接收到的指令转交给本地的 pvedaemon 守护进程。
- 节点B的
pvedaemon 最终执行具体的虚拟机/容器启停、迁移等操作。
因此,SSH 连接一旦在第二步握手失败,整条管理链路就中断了,Web 前端自然只能收到一个笼统的 500 错误。
四、根因定位:谁的“身份证”被换了?
经过梳理,问题根源水落石出:
- 密钥变更:之前我曾对
proxmox-a 进行过系统重装。重装后,我执行了 dpkg-reconfigure openssh-server,这导致节点A的整套 SSH 主机密钥(RSA/ECDSA/ED25519)被重新生成。
- 记录未更新:集群中的其他节点(本例中的节点B)的系统级 SSH 已知主机文件
/etc/ssh/ssh_known_hosts 里,仍然记录着节点A旧的密钥指纹。
- 严格的安全策略:SSH 客户端默认启用
StrictHostKeyChecking=yes。当它发现对方提供的密钥指纹与本地记录不符时,会出于安全考虑直接拒绝连接。
- 单向故障现象:这就导致了有趣的“单向通车”现象:
- B 访问 A:B 的
known_hosts 里存的是 A 的新指纹(因为重装后B可能重新连接过A并更新了记录),所以连接成功。
- A 访问 B:A 的
known_hosts 里存的还是 B 的旧指纹,但实际上B的密钥并未改变。此时A作为客户端去连接B,B出示了正确的(未变的)密钥,但A用旧的记录去核对,对不上,于是握手失败。
五、修复全流程(手把手版)
修复需要在“拒绝连接”的节点上进行,本例中就是在节点A上操作。
步骤 1:确认冲突记录的行号
错误信息已经明确给出了线索:
Offending RSA key in /etc/ssh/ssh_known_hosts:12
这表明在 /etc/ssh/ssh_known_hosts 文件的第 12 行,存在一条与目标主机(192.168.2.8)相关的无效 RSA 密钥记录。
步骤 2:一键删除过时的指纹记录
使用 ssh-keygen 命令清理旧记录。-R 参数会自动移除文件中所有关联到指定主机(IP或主机名)的密钥条目,涵盖各种算法,非常省心。
ssh-keygen -f /etc/ssh/ssh_known_hosts -R 192.168.2.8
步骤 3:重新建立连接并信任新指纹
现在,让节点A重新连接节点B,并在首次连接时自动接受并保存正确的主机密钥。使用 -o StrictHostKeyChecking=accept-new 选项可以安全地实现这一点。
ssh -o StrictHostKeyChecking=accept-new root@192.168.2.8 “echo SSH host key updated”
看到终端输出 “SSH host key updated” 字样,即表示新的主机密钥指纹已成功写入节点A的 known_hosts 文件。
步骤 4:最终验证
回到节点A的 8006 Web 管理界面。
- 进入“数据中心”视图下的集群概览。
- 点击节点
proxmox-b。
- 找到之前无法操作的容器(例如ID 101),点击“启动”。
此时,操作应该能够成功执行,容器顺利启动。同时,检查 /var/log/syslog,之前频繁出现的 ssh: handshake failure 错误日志也会消失。集群管理自此恢复“双向通车”。
六、可选加固与批量处理场景
1. 关闭严格主机密钥检查(不推荐用于生产环境)
在测试或频繁重建节点的环境中,可以临时放宽检查。在 /etc/ssh/ssh_config 中为特定网段添加配置:
Host 192.168.2.*
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
警告:这将完全禁用对该IP段的主机密钥验证,会丧失对中间人攻击的检测能力,仅适用于可信任的封闭测试环境。
2. 提前备份与恢复主机密钥(推荐做法)
在进行系统重装或迁移前,这是一个一劳永逸的优雅方案。
- 备份:重装前,将源节点的
/etc/ssh/ssh_host_* 密钥文件(通常包括 ssh_host_ecdsa_key, ssh_host_ed25519_key, ssh_host_rsa_key 等)打包备份。
- 恢复:新系统安装完成后,将备份的密钥文件原样放回
/etc/ssh/ 目录。
- 生效:执行
systemctl restart sshd 重启 SSH 服务。这样,集群中其他节点保存的该主机指纹将始终保持有效,完全无感知。
3. 使用自动化工具进行批量管理
如果你的集群节点数量众多,使用 Ansible 等自动化工具来批量更新密钥记录是高效的选择。以下是一个示例 playbook 片段:
- name: remove stale host key
known_hosts:
name: “{{ item }}”
state: absent
loop: “{{ groups[‘pve’] }}”
- name: scan and add new key
shell: ssh-keyscan -H {{ item }} >> /etc/ssh/ssh_known_hosts
loop: “{{ groups[‘pve’] }}”
这个 playbook 会先移除所有已知集群节点旧的记录,然后通过 ssh-keyscan 重新获取并添加所有节点当前正确的主机密钥。
七、小结
总结一下核心要点:PVE 集群的跨节点 Web 管理,底层完全依赖于 SSH 通信。一旦节点间记录的 SSH 主机密钥指纹不匹配,就会导致 Web 面板出现“集群已连接,但操作单向不通”的诡异状况。
解决之道就是“删除旧指纹,获取新指纹”这两步。对于因主机密钥变更引发的问题,通常几分钟内就能让集群恢复双向正常管理。
希望这篇从故障现象到根因分析,再到解决方案的完整记录,能帮助你快速定位并解决类似问题。欢迎在云栈社区分享你的运维经验和遇到的挑战,祝各位的 Proxmox VE 之旅一路绿灯!