SSH连接KVM虚拟机失败,九成问题出在网络层或SSH服务本身,按"Ping通→端口通→服务通"的顺序排查,配合virsh console先登进虚拟机内部确认状态,才是最高效的解法。
KVM虚拟机SSH连接失败是什么原因
KVM虚拟机的SSH连接和物理服务器不一样,中间隔着宿主机、虚拟网桥和虚拟化层,一次连接失败,可能在五个环节里出问题:
- 虚拟机没启动或内核卡死最常见,尤其是迁移或强制关机后重启的虚拟机
- 网络配置错误虚拟机的IP地址、网关、网桥配置不对,导致根本不在同一网段
- 防火墙或安全策略拦截宿主机和虚拟机各自的防火墙规则,以及
iptables的FORWARD链 - SSH服务异常sshd没启动、改了端口、监听地址被限制,或
authorized_keys权限不对 - 虚拟化网络模式限制默认NAT模式下,外部机器本来就连不进虚拟机,这不是故障,是设计如此
先判断报错的类型,再决定从哪里下手,SSH连接失败时的报错信息通常直接指向问题层级:
| 报错特征 | 问题层 |
|---|---|
Network is unreachable |
路由或网卡配置问题 |
Connection timed out |
防火墙拦截或网络不通 |
Connection refused |
SSH服务没起来或端口不对 |
Permission denied |
认证失败(密码/密钥问题) |
Host key verification failed |
SSH指纹不匹配 |
SSH连接超时:先查网络通不通
Connection timed out的意思是数据包发出去,但始终没有响应,这时候SSH服务本身可能压根没问题,流量在路上就被拦了。
第一步:从宿主机Ping虚拟机
# 在宿主机执行 ping -c 4 192.168.122.50
如果Ping得通,说明宿主机到虚拟机的二层/三层网络通,问题出在端口或服务层,跳到下一节。
如果Ping不通,用virsh console登录虚拟机检查:
# 查看虚拟机列表,确认运行状态 virsh list --all # 进入虚拟机的控制台 virsh console 你的虚拟机名称
进入虚拟机后,查看内部网络配置:
ip addr cat /etc/sysconfig/network-scripts/ifcfg-eth0 # RHEL/CentOS系 cat /etc/netplan/00-installer-config.yaml # Ubuntu系
第二步:检查虚拟网桥状态
宿主机上执行brctl show或ip addr show查看虚拟网桥,KVM默认创建的virbr0是NAT模式,地址段通常是168.122.0/24,如果虚拟机没有和宿主机在同一个网段,或者网桥接口不在UP状态,自然连不上。
行业共识认为,80%左右的自建KVM环境SSH问题,最后都指向网桥配置或iptables FORWARD规则。
第三步:检查宿主机防火墙
宿主机防火墙拦了病毒机的流量,这种情况在CentOS 7以上和Ubuntu的ufw上很常见:
# 查看防火墙是否拦截了流量 firewall-cmd --list-all # firewallD iptables -L -n -v | grep FORWARD # iptables # 如果显示DROP规则,先放行虚拟网络流量 firewall-cmd --permanent --zone=trusted --change-interface=virbr0 firewall-cmd --reload
SSH端口不通:可能是防火墙,也可能是sshd没监听
Ping通了但SSH连不上,重点查端口监听和防火墙放行情况。
从宿主机测试端口是否正常
# 测试虚拟机的22端口是否开放 telnet 192.168.122.50 22 nc -vz 192.168.122.50 22
端口不通时,先检查sshd是否在运行:
# 通过virsh console进入虚拟机后执行 systemctl status sshd # 或 systemctl status ssh ss -tlnp | grep 22
如果sshd没启动,启动并设置开机自启:
systemctl start sshd systemctl enable sshd
坑点在于,虚拟机内部的防火墙一样会拦SSH,很多人在宿主机折腾半天,实际是虚拟机自己的firewalld拦了22端口:
# 在虚拟机内部执行 firewall-cmd --permanent --add-service=ssh firewall-cmd --reload
改了SSH端口如何快速定位
如果你自定义过SSH端口(比如改为22026),但忘了记下来,先在宿主机扫描虚拟机端口:
nmap -sS 192.168.122.50
或者直接在虚拟机内部看:
ss -tlnp | grep ssh grep -i "^Port" /etc/ssh/sshd_config
SSH监听了一个自定义端口,但你按默认22去连,自然是Connection refused。
KVM虚拟机SSH连接失败和桥接网络模式的关系
这是KVM里最容易踩的坑,创建虚拟机时用了默认的NAT网络(virbr0),虚拟机可以访问外部网络,但外部网络访问不了虚拟机,如果你在家里或办公室局域网里想用SSH连虚拟机,必须在创建虚拟机时配置桥接模式。
两种网络模式的本质区别
| 网络模式 | 特点 | SSH连通性 |
|---|---|---|
| NAT(默认virbr0) | 虚拟机共享宿主机IP,宿主机转发流量 | 宿主机可连虚拟机,局域网其他机器不可直连;如果想连,需要端口转发如iptables -t nat -A PREROUTING -p tcp --dport 2222 -j DNAT --to-destination 192.168.122.50:22 |
| 桥接(br0) | 虚拟机直接挂在物理网络上,拥有独立IP | 局域网内所有机器可直接SSH连接 |
检查当前虚拟机用的什么网络模式
# 查看虚拟机网络配置 virsh dumpxml 你的虚拟机名称 | grep -A 10 "<interface"
输出里如果看到<source network='default'/>,说明用的NAT模式,想要桥接,需要先创建网桥:
# 在宿主机创建网桥(以CentOS为例) nmcli con add type bridge ifname br0 con-name br0 nmcli con add type bridge-slave ifname eth0 master br0 nmcli con up br0
然后把虚拟机网络接口从network default改为bridge br0:
virsh edit 你的虚拟机名称
找到<interface>段,把:
<interface type='network'> <source network='default'/>
改为:
<interface type='bridge'> <source bridge='br0'/>
改完重启虚拟机,进系统后用ip addr确认拿到了局域网同网段的IP,再尝试SSH。
桥接后仍然连不上的排查要点
- 物理网卡的混杂模式:切换桥接后,宿主机物理网卡需要支持混杂模式,用
ip link set eth0 promisc on开启,但通常桥接会自动设置 - virbr0的IP残留:NAT模式切换到桥接后,去掉了
virbr0的IP地址,否则路由表会有冲突:ip addr flush dev virbr0
- 虚拟机内网卡名称变化:从NAT改成桥接后,虚拟机里的网卡名称可能从
eth0变成ens3或enp1s0,配置文件里的设备名不对就会出现"连接失败"。
认证失败:密码和密钥问题
SSH能ping通、端口通,但卡在Permission denied,这是认证环节的问题。
排查密码认证
确保虚拟机里设置了正确的密码:
# 通过virsh console进入虚拟机 passwd 你的用户名
如果SSH配置文件禁用了密码登录,改回来:
# /etc/ssh/sshd_config PasswordAuthentication yes # 改完重启sshd systemctl restart sshd
排查密钥认证
密钥认证失效,最典型的原因是文件权限不对:
# 在虚拟机内部检查用户目录权限 ls -la ~/.ssh/ chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys # 检查sshd_config是否允许密钥认证 grep -i "PubkeyAuthentication" /etc/ssh/sshd_config
另外注意~/.ssh目录的属主必须匹配登录用户,如果之前是用root创建了密钥然后转给普通用户,权限没对齐,也会被拒绝。
SELinux导致连接失败的隐蔽坑
Permission denied还有一个极隐蔽的原因SELinux对sshd的上下文标签不正确,尤其是自定义了authorized_keys文件位置时:
# 在虚拟机内部恢复正确标签 restorecon -Rv ~/.ssh
对于CentOS和Rocky系用户,SSH连接失败多数情况下可以先临时执行setenforce 0验证,如果问题消失,就是SELinux的策略问题,再针对性地调整布尔值。
KVM虚拟机SSH连接失败后还有哪些替代远程方案
SSH连不上不代表虚拟机彻底废了,下面几条备用路径,至少能保住操作虚拟机的通道:
-
virsh console串口控制台:这是最可靠的兜底方案,不依赖网络协议,直接进虚拟机内部,前提是虚拟机创建时配置了串口设备,如果没有,在
virsh edit里添加:<console type='pty'> <target type='serial' port='0'/> </console> <serial type='pty'> <target type='isa-serial' port='0'> <model name='isa-serial'/> </target> </serial>同时在虚拟机内部启用串口登录服务:
systemctl enable serial-getty@ttyS0.service --now
-
VNC远程连桌面:用
virt-manager打开图形管理界面,在虚拟机窗口登录,修复SSH的配置,适合不习惯纯命令行的用户。 -
宿主机上直接挂载虚拟磁盘修改配置:作为最后手段,关机后用
guestmount或virt-customize挂载虚拟机的磁盘镜像,直接修改其中的sshd配置,适合虚拟机系统完全卡死的情况。
# 安装guestfs工具后 virt-customize -a /var/lib/libvirt/images/你的虚拟机.qcow2 --run-command 'systemctl enable sshd' virt-customize -a /var/lib/libvirt/images/你的虚拟机.qcow2 --run-command 'sed -i "s/#PermitRootLogin./PermitRootLogin yes/" /etc/ssh/sshd_config'
KVM虚拟机SSH连接失败和VMware ESXi故障有什么区别
很多从VMware ESXi切到KVM的用户觉得"KVM问题多",其实区别不在稳定性,而在排查思路的差异:
- 虚拟网络架构不同:VMware ESXi自带标准交换机/分布式交换机,配置层级更清晰;KVM的桥接、NAT、macvtap共用一套Linux网络栈,灵活但排查点多,KVM里发生SSH连接失败,要额外考虑Linux的iptables、netfilter和路由表。
- 控制台访问方式不同:ESXi有远程Web控制台,KVM的
virsh console依赖串口设备,如果创建虚拟机时没配串口,就少了一条兜底路径。 - 日志系统不同:ESXi日志集中在vCenter里;KVM的日志分散在宿主的
/var/log/libvirt/qemu/虚拟机名.log、journalctl -u libvirtd和虚拟机内部的/var/log/secure三处。
如果原先是VMware运维出身,切换到KVM时建议先花半小时熟悉virsh命令行和brctl网桥工具,这比遇到问题再翻文档高效得多。
常见问题快速解答
KVM虚拟机怎么判断SSH失败是网络问题还是服务问题?
用三层递进测试法:先Ping IP,Ping不通是网络问题;Ping通了但telnet IP 22不通,是端口或防火墙问题;端口通但登录失败,是SSH服务配置或认证问题,每一步都能定位一个层级,直接对准方向排查。
为什么KVM虚拟机用virsh console能登录但SSH被拒绝?
虚拟机内部网络服务没启动、虚拟机的防火墙拦了22端口,或SSH服务只监听在某个特定IP上,先执行ip addr看IP配置是否正常,再看firewall-cmd --list-all是否放行了SSH,最后检查ss -tlnp | grep ssh确认SSH的监听地址,如果监听的是0.0.1,说明sshd_config里配了ListenAddress,删掉后重启sshd即可。