你是不是也遇到过这样的场景:VMware 里装好了 Ubuntu,虚拟机里ip addr看 IP 明明正常,宿主机 Windows 打开 VS Code 的 Remote-SSH 或者 PuTTY 连过去,光标卡住十几二十秒,最后弹出一句Network error: Connection timed out。更让人崩溃的是,有人告诉你“检查防火墙”“重启 SSH 服务”,你照做了一遍,问题还在。
这个错误我前前后后踩了无数次,也帮不少人排查过。它表面上就一句话,但背后涉及虚拟机的网络模式、sshd 的监听配置、宿主机和虚拟机两侧的防火墙、甚至客户端工具的代理设置。好消息是,绝大多数情况下原因就那么几个,只要按链路一层层剥,几分钟内就能定位。这篇文章把我自己的排查思路、用过的命令、踩过的坑全部整理出来,希望能帮你少走弯路。
1. Connection timed out 的本质:数据包走到哪一步才被丢掉
先别急着敲命令,搞清楚这个报错到底在说什么,比什么都重要。
1.1 超时不是“连不上”,而是“没人应答”
很多人一看到Network error: Connection timed out,第一反应是“网络不通”。其实这个描述太笼统了。Connection timed out在 TCP 层面意味着:你的客户端发出了 SYN 包,但在一段时间内(通常是 20 秒左右)没有收到对端的 SYN-ACK 响应,最后客户端主动放弃。
这里有两种典型情况值得区分:
- 目标主机根本不可达:比如 IP 段不对,或者虚拟机没开机,数据包发出去直接石沉大海。
- 目标可达但端口被丢弃:比如 ping 得通,但 22 端口被防火墙挡了,数据包被静默丢弃,客户端收不到任何回应,最终表现为超时。
这个区分非常关键。如果 ping 不通,是网络层问题;如果 ping 得通但 SSH 端口连不上,那是传输层或服务层问题。排查路径完全不同。
1.2 排查前先确认三件事:IP、端口、协议
在动手“修”之前,先把下面三个基础信息确认清楚,能省掉后面八成瞎忙:
| 检查项 | 正确姿势 | 常见误区 |
|---|---|---|
| 目标 IP | 在虚拟机里执行ip addr或ifconfig确认当前实际 IP | 凭记忆填一个“上次用的 IP”,DHCP 一变就超时 |
| 目标端口 | SSH 默认 22,VNC 常见 5901,确认服务实际监听端口 | 默认认为就是 22,其实不少人改过端口 |
| 连接协议 | 确认客户端和服务端用的 SSH 版本一致、VNC 密码方式一致 | SSH 和 Telnet 混着用,协议对不上 |
我遇到过不止一个朋友,信誓旦旦说“虚拟机 IP 没变”,结果ip addr一看,IP 早就从192.168.88.128变成了192.168.88.135。所以第一步永远是进虚拟机确认现状,不要靠记忆。
2. 虚拟机网络模式没选对,后面排查全白费
VirtualBox 和 VMware 都提供了多种网络模式,很多人只会在创建虚拟机时选个默认值,从没搞清楚其中的差别。这个选择直接决定了宿主机到底能不能连进虚拟机,也决定了你后续要调哪些参数。
2.1 NAT、桥接、Host-Only 的核心区别
我把三种最常见模式的行为差异整理成一张表,你对照自己场景看:
| 网络模式 | 虚拟机能否访问外网 | 宿主机能否访问虚拟机 | 其他主机能否访问虚拟机 |
|---|---|---|---|
| NAT | 能 | 通常能,但依赖具体实现(VMware 可用 VMnet8 直连) | 不能 |
| 桥接 | 能 | 能,只要在同一网段 | 能,同一局域网内就行 |
| Host-Only | 不能访问外网(或需额外配置) | 能 | 不能 |
如果你只是想开发调试,在宿主机上用 VS Code 连虚拟机,NAT 模式是足够用的。但在实际排障中,很多人卡在一个误区里:虚拟机用的是 NAT 模式,却抱怨“同一台路由器下另一台电脑连不上”,这从网络结构上就不成立。
2.2 “能上网但 SSH 不通”的典型配置陷阱
NAT 模式下最反直觉的一点是:虚拟机可以通过 NAT 上网,但外部设备不一定能反向连进虚拟机。在 VMware 里,宿主机可以通过VMnet8直接访问虚拟机的 IP,但如果你在虚拟机里做 DHCP 地址变化、或者 VMware 的 NAT 服务没起来,就会出现“虚拟机自己能上网,宿主机连不上”的怪现象。
桥接模式也有它的坑。桥接意味着虚拟机要跟宿主机使用同一局域网,如果公司网络做了 MAC 地址绑定,或者路由器开启了 AP 隔离,虚拟机的桥接网络就会形同虚设。这个时候你ping 宿主机可能通,但其他设备就是访问不到虚拟机。
2.3 静态 IP 配置建议:避免 DHCP 变动导致的二次失败
DHCP 租约一到期,虚拟机 IP 变了,你手头的连接自然超时。与其每次去查 IP,不如直接给虚拟机配静态 IP。我比较推荐的做法是:在 NAT 模式下,把虚拟机的 IP 固定到 VMnet8 网段中一个不冲突的地址。
以 Ubuntu 22.04+ 的 Netplan 配置为例:
network: version: 2 ethernets: ens33: dhcp4: no addresses: - 192.168.88.128/24 routes: - to: default via: 192.168.88.2 nameservers: addresses: - 192.168.88.2 - 223.5.5.5其中网关要填 NAT 模式的虚拟网关地址,VMware 里通常是192.168.88.2,VirtualBox 里默认是10.0.2.2。不确定的话,在改静态 IP 之前先看看当前 DHCP 分配的网关是多少。
3. sshd 服务端监听与认证配置:这些细节决定能不能连上
网络层通了之后,下一个要排查的就是服务端。尤其很多人用的不是原生 Ubuntu 服务器镜像,而是在桌面版里手动装的openssh-server,各种路径上的问题更容易被忽略。
3.1 监听地址是 0.0.0.0 还是 127.0.0.1
SSH 服务如果只监听了回环地址127.0.0.1,那它在宿主机看来就是“不存在”的。你可以通过下面的命令确认:
ss -tlnp | grep sshd正常输出类似:
LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=1234,fd=3))如果你看到的是127.0.0.1:22,那就说明配置文件/etc/ssh/sshd_config里有ListenAddress 127.0.0.1,把它注释掉或者改成0.0.0.0,然后重启 SSH 服务。
3.2 服务没起来?系统日志里找真相
我排查过好几次虚拟机 SSH 超时,最后发现 sshd 根本没在运行。桌面版 Ubuntu 默认不会开机自启 SSH 服务,需要手动确认:
systemctl status ssh如果服务是inactive或failed,启动它:
sudo systemctl start ssh sudo systemctl enable ssh启动失败的话,千万别反复重启,先看日志:
journalctl -u ssh --since "5 minutes ago"或者看/var/log/auth.log。很多时候失败原因是/etc/ssh/sshd_config里某一行语法写错了,日志里会清楚告诉你“Bad configuration option”在哪。
3.3 密钥与密码认证的坑
另一种隐蔽的超时/失败是认证阶段引起的。虽然严格来说认证失败通常报的是Permission denied,但如果客户端配置了错误的密钥,且服务端关闭了密码认证,有些客户端会不断重试,直到超时。排查方法很简单:用ssh -vvv看详细输出,它会明确告诉你走到了哪一步。
如果你发现日志里有大量Failed password或Connection reset by ...,要考虑是不是认证方式不对。另外,/etc/ssh/sshd_config里的UsePAM、PasswordAuthentication也需要确认,确保密码认证没有被无意关掉。
4. 防火墙是超时报错的头号嫌疑犯:如何系统性排除
如果把所有导致Connection timed out的原因按概率排序,防火墙绝对排第一。但它也是最容易排查和解决的,只要用对方法。
4.1 Linux 防火墙规则检查清单
进入虚拟机,依次确认以下内容:
sudo ufw status如果状态是active,看规则里有没有放行 22 端口。没有的话执行:
sudo ufw allow 22/tcp sudo ufw reload如果你用的是 CentOS / Rocky Linux 等系统,则需要关注 firewalld:
sudo firewall-cmd --list-all sudo firewall-cmd --add-service=ssh --permanent sudo firewall-cmd --reload还有一种情况是 ufw 显示inactive,但系统里同时装了 iptables 服务,规则被 iptables 接管了。所以我习惯直接用iptables -L -n看一眼是否有可疑的 DROP 规则。有些加固脚本会在INPUT链上默认设为 DROP,没放行 22 就导致外部连接一直超时。
4.2 Windows 宿主机的出站/入站规则
很多时候问题不在虚拟机,而在宿主机 Windows 的防火墙。尤其是 Windows 11 上安装 VMware 或 VirtualBox 后,首次运行会弹窗询问是否允许虚拟机网络服务共享网络,如果当时误点了取消,后续连接虚拟机就会超时。
排查方法:打开“Windows Defender 防火墙”-“高级设置”,查看“入站规则”里是否有 VMware NAT Service、VMware Authorization Service 相关的放行规则。如果没有,手动添加放行,或者直接在网络类型里选择“允许”:
netsh advfirewall firewall add rule name="VMware NAT" dir=in action=allow program="C:\Program Files (x86)\VMware\VMware Workstation\vmware-nat.exe" enable=yes需要注意程序路径以你本机实际安装位置为准。VirtualBox 用户则关注VBoxSVC.exe和VirtualBox.exe。
4.3 VMware 虚拟网络编辑器的隐性问题
VMware 里有一个几乎人人都见过但很少深究的入口:“编辑”-“虚拟网络编辑器”。打开之后,里面会列出 VMnet0、VMnet1、VMnet8 等虚拟网卡,其中隐藏着很多导致连接超时的元凶:
- VMnet8 的子网 IP 被改动:如果子网和你虚拟机里的静态 IP 不在同一段,连接必然失败。
- DHCP 设置异常:若 DHCP 功能被关闭,而系统里又用了动态获取,虚拟机会拿不到 IP。
- NAT 服务未启动:Windows 服务里
VMware NAT Service如果没启动,NAT 模式虚拟机无法访问外网,宿主机也难以反向访问。
检查方式很直接:在 Windows 服务管理器中确认 VMware 相关服务全部正在运行,然后回到虚拟网络编辑器,点“恢复默认设置”,再把 VMnet8 的子网设成你记住的网段。这一招虽然粗暴,但能解决大量由配置错乱导致的超时问题。
5. 客户端与工具的干扰项:VS Code、PuTTY、Xshell 各有各的坑
网络通了、服务端正常、防火墙也放行了,但连接还是超时?这时候把问题放到客户端工具上,你会发现问题还有很多。
5.1 VS Code Remote-SSH 超时的常见原因
VS Code 的 Remote-SSH 插件是现在最主流的远程开发方式。它看起来只是一个 SSH 连接,实际上会在远端下载安装一个 vscode-server 服务端,这个过程更容易受到干扰。
最近实测遇到比较多的一个报错是stream disconnected before completion: transport error: network error: error。它通常代表 SSH 本身已经建立了,但在传输 vscode-server 相关数据时连接被重置。常见原因如下:
- 远端磁盘空间不足,导致 vscode-server 解压失败;
- 网络不稳定,大文件传输中断;
- 服务端
.vscode-server目录权限不对,导致写入失败。
对应解法:先手动 SSH 连进虚拟机,删除旧的服务端缓存,再重新连接:
rm -rf ~/.vscode-server顺便检查磁盘:
df -h如果/分区使用率接近 100%,先清理日志和临时文件再重试。
5.2 PuTTY 连接超时的排查思路
PuTTY 报Network error: Connection timed out时,比较直接。在确认 IP、端口都没问题后,检查 PuTTY 的“连接”设置里是否设置了超过合理范围的超时时间。默认是 5 秒到 240 秒,如果设置得太短,跨网段连接时就会因为握手慢而误报超时。同时确认左边“Session”里保存的 Host Name 没有带着奇怪的空格或隐藏字符。
5.3 代理配置与网络环境干扰
很多人忽略的是,宿主机或局域网出口如果挂了代理,SSH 连接也会被代理干扰。VS Code 这类工具默认会读取系统代理环境变量,如果代理指向了一个不可用的地址,连接就会在长久的等待后超时。
我自己遇到过最典型的一种情况:系统设置了全局代理,VS Code Remote-SSH 走了这个代理去连虚拟机的内网 IP,结果代理转发失败,表现为超时。排查时可以临时关闭代理,或者在 VS Code 的settings.json里针对 SSH 连接禁用代理:
"remote.SSH.useLocalServer": true, "remote.SSH.shellIntegration.enabled": false对于 Xshell、FinalShell 这类工具,同样注意它们自带的“代理设置”和“跳板机设置”,有时候你可能不小心把一个无用的代理配置带进了会话,导致连接卡住。
6. 实测排查链路:三个典型场景的完整排障过程
理论说了这么多,举三个我真实遇到的案例,把排查链路完整串一遍。你会发现,前面提到的那些点在实际中常常叠加出现。
6.1 场景一:NAT 模式下能上网但宿主机 SSH 超时
现象:Ubuntu 虚拟机里ping baidu.com通,但宿主机 SSH 报超时。
排查过程:
- 在虚拟机里
ip addr确认 IP 是192.168.88.128,一切正常; - 在宿主机
ping 192.168.88.128,发现完全不通; - 检查 VMnet8 虚拟网卡,发现它被 Windows 休眠后重置成了
192.168.88.1,子网掩码也对,但网卡状态显示“未识别的网络”; - 打开“网络连接”,禁用再启用 VMnet8,问题消失。
这里面真正的原因是 Windows 网络栈状态异常。虚拟机没有任何问题,纯粹是宿主机的虚拟网卡“假死”了。类似的“假死”还会影响 VMware NAT 服务,优先检查服务状态和网卡状态是这类问题的通用解法。
6.2 场景二:桥接模式配了静态 IP,重启后失联
现象:虚拟机之前可以通过192.168.1.100被宿主机访问,某次重启后连接超时,虚拟机界面能看到已登录系统。
排查过程:
- 在虚拟机里查看
ip addr,发现网卡虽然有192.168.1.100,但链路状态显示state DOWN; - 检查 NetworkManager 状态正常,但
ens33始终没有被激活; - 手动执行
sudo ip link set ens33 up后,网络恢复,但重启后再次失效; - 最终检查 Netplan 配置文件,发现
ens33少写了optional: true,且renderer与桌面版 NetworkManager 冲突。
桥接模式下遇到重启失联,优先查看 Netplan 和 NetworkManager 之间的协作关系。桌面版 Ubuntu 默认用 NetworkManager,如果 Netplan 里强制指定了networkd,就会出现网卡不够活跃、连接超时的现象。稳妥做法是统一用 NetworkManager 管理,或者干脆用服务器版镜像来做远程开发。
6.3 场景三:防火墙放行端口后仍然超时
现象:ufw status显示 22/tcp 已放行,宿主机仍报超时。
排查过程:
- 宿主机
telnet 192.168.88.128 22,卡住不动,说明 22 端口没有任何响应; - 在虚拟机内执行
ss -tlnp | grep 22,发现 sshd 监听的是0.0.0.0:2222——原来之前有人把端口改成 2222,防火墙放行的还是默认 22; - 把 /etc/ssh/sshd_config 里的
Port改回 22,重启服务,连接成功。
这个案例听起来简单,但现实中特别常见。任何服务只要改过端口,防火墙规则、客户端端口、服务监听端口必须三处同步。漏一处,结果就是“检查什么都正常,但就是连不上”。
最后分享几条个人习惯
排查这类超时问题,我自己的习惯是先用一句话锁定故障层:链路层看ping,端口层看telnet或nc -vz,服务层看ss -tlnp,认证层看ssh -vvv。不做任何假设,一步步验证,基本都能快速收敛到真因。
还有一个很实用的经验:想快速验证是不是防火墙导致的超时,可以在虚拟机上临时关闭防火墙再试一次。如果关了就通,那问题一定在防火墙规则上;如果关了还不通,就不用再花时间反复检查防火墙了。同样道理,宿主机 Windows 的防火墙也可以在测试时临时关闭,但注意测试完恢复,尤其是办公网络环境下不要大意。
最后,如果你前面所有步骤都查了还是没找到原因,建议在 VMware 的虚拟网络编辑器里执行“恢复默认设置”,重置 VMnet 网卡和 NAT 服务的配置。这个操作我已经用它救回过好几次顽固问题,虽然看起来有点“玄学”,但本质上是把虚拟机网络栈中残留的错误配置全部清掉了。之后重新配好静态 IP,大概率能恢复正常。