虚拟机没有 IP 时,如何通过 SSH 隧道进入 KVM 控制台

一台 KVM 虚拟机无法通过 SSH 连接,不一定意味着它已经失去控制。虚拟机可能尚未获取 DHCP 地址、静态网络配置错误、系统停在磁盘解密界面,甚至根本还没有启动到网络服务。

这类故障的可靠处理方式,是绕过 guest 网络,从 KVM 宿主机直接进入虚拟机的 VGA 控制台。本文介绍一条适用于 Windows、macOS 和 Linux 的通用路径:

运维电脑 -> SSH 隧道 -> KVM 宿主机 -> QEMU VNC -> 虚拟机 VGA/tty1

整个过程不要求运维电脑与虚拟机处于同一局域网,也不要求事先知道虚拟机 IP。

先分清 tty1 和 ttyS0

排查前最容易混淆的是两个终端:

终端 含义 常见接入方式
tty1 Linux 第一虚拟终端,显示在 VGA 屏幕上 VNC、SPICE、物理显示器
ttyS0 第一串口终端 virsh console <vm-name>

virsh console 通常连接的是 ttyS0,不是 tty1。如果 guest 没有设置 console=ttyS0,或者没有启用 serial-getty@ttyS0.service,执行 virsh console 后可能只有空白画面。

需要查看 BIOS、启动日志、磁盘解密提示或图形化登录界面时,应使用 VNC 进入 VGA 控制台。

一、在宿主机确认虚拟机状态

先通过 SSH 登录 KVM 宿主机,然后进行只读检查:

virsh list --all
virsh dominfo <vm-name>
virsh domiflist <vm-name>
virsh net-list --all
virsh net-dhcp-leases default

如果虚拟机处于 shut off,没有 DHCP 租约是正常现象。QEMU 进程和 VNC 端口通常也只会在虚拟机运行时出现。

继续确认虚拟机是否配置了 VNC 和串口:

virsh dumpxml <vm-name> | sed -n '/<graphics/,/<\/graphics>/p'
virsh dumpxml <vm-name> | sed -n '/<serial/,/<\/serial>/p'

典型 VNC 配置如下:

<graphics type="vnc" port="5901" autoport="no" listen="127.0.0.1">
  <listen type="address" address="127.0.0.1"/>
</graphics>

推荐只监听 127.0.0.1。VNC 协议本身通常不提供足够的传输保护,直接监听公网或办公网地址会扩大攻击面。

二、获得授权后启动虚拟机

启动虚拟机会改变运行状态。在生产环境中,应先确认维护窗口、业务归属和磁盘占用情况。

virsh start <vm-name>
virsh domstate <vm-name>
virsh vncdisplay <vm-name>
virsh ttyconsole <vm-name>

假设 virsh vncdisplay 返回:

:1

通常对应 TCP 端口 5901,计算方式为 5900 + display number。仍应使用监听结果进行确认:

ss -ltnp | grep ':5901'

三、建立 SSH 本地端口转发

下面的命令把运维电脑的 127.0.0.1:5901 转发到宿主机的 127.0.0.1:5901

ssh -N \
  -L 5901:127.0.0.1:5901 \
  -p <HOST_SSH_PORT> \
  -i ~/.ssh/id_ed25519 \
  -o ExitOnForwardFailure=yes \
  -o ServerAliveInterval=30 \
  -o ServerAliveCountMax=3 \
  root@<HOST_ADDRESS>

参数含义:

  • -N:只建立隧道,不执行远程命令。
  • -L:创建本地端口转发。
  • ExitOnForwardFailure=yes:端口绑定失败时立即报错,避免留下一个看似正常但不可用的 SSH 会话。
  • ServerAliveIntervalServerAliveCountMax:及时发现链路断开。

如果宿主机必须经过标准 SSH 堡垒机访问,可以加入 -J

ssh -N \
  -J <BASTION_USER>@<BASTION_HOST>:<BASTION_PORT> \
  -L 5901:127.0.0.1:5901 \
  -p <HOST_SSH_PORT> \
  -i ~/.ssh/id_ed25519 \
  root@<HOST_ADDRESS>

如果使用 HTTP CONNECT 代理,可通过 OpenSSH 的 ProxyCommand 调用 corkscrew

ssh -N \
  -L 5901:127.0.0.1:5901 \
  -p <HOST_SSH_PORT> \
  -i ~/.ssh/id_ed25519 \
  -o ExitOnForwardFailure=yes \
  -o 'ProxyCommand=corkscrew <PROXY_HOST> <PROXY_PORT> %h %p' \
  root@<HOST_ROUTE>

四、Windows 客户端

直接 SSH 或 SSH 堡垒机

Windows 10 和 Windows 11 可以安装系统自带的 OpenSSH Client。在 PowerShell 中执行:

ssh.exe -N `
  -L 5901:127.0.0.1:5901 `
  -p <HOST_SSH_PORT> `
  -i "$env:USERPROFILE\.ssh\id_ed25519" `
  -o ExitOnForwardFailure=yes `
  root@<HOST_ADDRESS>

经过标准 SSH 堡垒机时:

ssh.exe -N `
  -J <BASTION_USER>@<BASTION_HOST>:<BASTION_PORT> `
  -L 5901:127.0.0.1:5901 `
  -p <HOST_SSH_PORT> `
  -i "$env:USERPROFILE\.ssh\id_ed25519" `
  root@<HOST_ADDRESS>

检查本地端口:

Get-NetTCPConnection -LocalPort 5901 -State Listen
Test-NetConnection 127.0.0.1 -Port 5901

然后使用 TigerVNC Viewer、RealVNC Viewer 或 TightVNC Viewer 连接:

127.0.0.1:5901

HTTP CONNECT 场景

Windows 原生环境并不默认提供 corkscrew。更稳定的方式是在 WSL 中安装并运行:

sudo apt-get update
sudo apt-get install -y corkscrew

随后在 WSL 中执行前文的 ProxyCommand=corkscrew ... 隧道命令。私钥应放到 WSL 的 ~/.ssh/ 并设置权限:

chmod 600 ~/.ssh/id_ed25519

五、macOS 客户端

macOS 自带 OpenSSH 和屏幕共享客户端。需要 HTTP CONNECT 时,可以安装 corkscrew

brew install corkscrew

建立隧道后,打开系统自带屏幕共享:

open 'vnc://127.0.0.1:5901'

也可以在 Finder 中选择“前往 -> 连接服务器”,输入:

vnc://127.0.0.1:5901

六、Linux 客户端

Debian 或 Ubuntu:

sudo apt-get update
sudo apt-get install -y corkscrew tigervnc-viewer

Fedora 或 RHEL 系发行版的软件包名称可能略有不同:

sudo dnf install -y corkscrew tigervnc

建立 SSH 隧道后连接:

vncviewer 127.0.0.1:5901

桌面环境也可以使用 Remmina,新建 VNC 连接并填写 127.0.0.1:5901

七、如何验证隧道真的可用

macOS 和 Linux 可以直接读取 VNC 协议头:

nc -w 3 127.0.0.1 5901 | head -c 32

正常结果以 RFB 开头,例如:

RFB 003.008

Windows 可以使用:

Test-NetConnection 127.0.0.1 -Port 5901

TCP 测试成功只能证明端口可达。最终仍应使用 VNC Viewer 确认可以看到虚拟机画面。

八、常见故障及判断边界

现象 故障位置 建议检查
SSH 无法登录宿主机 SSH、代理或路由层 ssh -vv、代理连通性、密钥权限
本地 5901 没有监听 隧道建立失败或端口冲突 SSH 输出、ExitOnForwardFailure
VNC 连接被拒绝 QEMU 没有监听目标端口 VM 状态、virsh vncdisplayss
VNC 连接后黑屏 guest 未启动完成或停在固件/解密阶段 按 Enter、等待启动、检查 QEMU 日志
guest 没有 DHCP 租约 guest 网络尚未工作 继续在 tty1 检查网卡和网络服务
virsh console 空白 guest 未启用 ttyS0 输出 改走 VNC;维护后配置串口控制台

本地端口已被占用

可以把本地端口改成 15901,远端端口仍保持 5901

ssh -N -L 15901:127.0.0.1:5901 root@<HOST_ADDRESS>

然后让 VNC Viewer 连接:

127.0.0.1:15901

九、安全注意事项

  1. 不要把无密码 VNC 直接暴露到公网或不受信任网络。
  2. 优先让 QEMU VNC 只监听宿主机 127.0.0.1
  3. 使用 SSH 隧道提供传输加密和身份认证。
  4. 不要在脚本、工单、截图或文章中泄露真实私钥、内部域名、节点标识和网络拓扑。
  5. 启动、强制关机、修改 libvirt XML 或挂载 guest 磁盘前,应取得变更授权。
  6. 完成操作后关闭 VNC Viewer,并在隧道终端按 Ctrl+C

十、结语

当虚拟机网络失效时,控制面应与数据面分离。guest IP、路由和 SSH 都属于虚拟机内部网络路径;VNC 和串口则由宿主机提供,是处理启动期故障的重要兜底能力。

实际运维中,建议同时配置两条路径:

  • VNC 或 SPICE,用于 VGA、tty1、固件和磁盘解密界面。
  • serial console,用于纯终端环境和自动化接管。

配合只监听 loopback 的控制台、SSH 隧道和清晰的变更门禁,即使不知道虚拟机 IP,也能安全、可审计地恢复控制。

标签: Linux, KVM

添加新评论