【网络与代理】WSL 多网段服务访问超时:防火墙、Docker 路由与 SSH 代理排查
问题背景
一台 Windows + WSL2 服务器同时运行了 Web 服务、SSH、Docker 和本地代理。服务器所在网段可以正常访问这些服务,但另一个内网网段的机器始终连接超时。
最初看起来像 Windows 防火墙没有放行端口。实际排查后发现,问题由两层配置叠加造成:
- Windows 防火墙需要允许可信内网访问 WSL 中的 TCP 服务。
- WSL 里的 Docker 网桥与真实内网网段重叠,导致返回数据走错网卡。
第二点更隐蔽。即使端口已经监听、防火墙规则也正确,只要回程路由错误,客户端看到的仍然只是超时。
先确认服务真的在监听
不要一开始就改防火墙。先在 WSL 中确认服务监听地址:
1 | ss -lntp |
如果服务只监听 127.0.0.1,其他机器无法直接连接。需要对内网提供服务时,应让它监听 0.0.0.0:<PORT>,或者通过反向代理暴露。
然后分别从服务器本机和客户端测试:
1 | # 在服务器本机测试 |
本机成功而远程超时,说明应用大概率正常,问题位于防火墙、转发或路由层。
Windows 防火墙应该按信任边界配置
如果服务器运行的端口很多,逐个维护端口规则很容易漏。对于确定可信的 Private 网络,可以建立一条统一的 TCP 入站规则:
1 | New-NetFirewallRule ` |
这条规则的含义是:
- 仅对 Windows 识别为
Private的网络生效。 - 允许访问本机全部 TCP 端口。
Public网络不受影响,仍执行默认阻止策略。- UDP 不统一开放,需要时再单独添加规则。
先确认当前网络配置文件,避免把不可信网络误设为 Private:
1 | Get-NetConnectionProfile |
如果只运行少量固定服务,按端口放行仍然更稳妥。全 TCP 放行适合端口较多、网络边界清楚、客户端均可信的内网环境。
防火墙放行后仍然超时,就检查路由
这次排障中,防火墙规则生效后,同网段客户端已经可以访问,但另一个网段仍然超时。此时继续添加端口规则没有意义,需要检查 WSL 的路由表:
1 | ip -4 addr |
重点查看 Docker 创建的网桥:
1 | docker network ls |
典型冲突如下:
1 | 真实客户端网段:<CLIENT_SUBNET> |
例如,真实客户端位于某个 /24 网段,而 Docker 恰好创建了覆盖它的 /16 网桥。Linux 根据路由表选择出口时,会把返回客户端的数据送进 Docker 网桥,而不是发往真正的局域网网关。
请求能够到达服务器,但响应回不到客户端。客户端最终只看到连接超时。
可以用下面的命令直接确认内核准备走哪条路:
1 | ip route get <CLIENT_IP> |
如果输出中的设备是 docker0 或其他 Docker bridge,而不是实际连接局域网的网卡,就找到了根因。
用更精确的静态路由修复回程路径
为真实客户端网段添加一条更精确的路由:
1 | sudo ip route replace <CLIENT_SUBNET> via <LAN_GATEWAY> dev <LAN_INTERFACE> |
例如,Docker 占用了较大的 /16,真实内网使用其中一个 /24。新增的 /24 路由比 /16 更精确,因此内核会优先把数据交给真实局域网网卡。
再次检查:
1 | ip route get <CLIENT_IP> |
确认输出中的网关和网卡正确后,再从客户端测试 SSH 和 Web 服务:
1 | nc -vz <SERVER_IP> 22 |
如果可以调整 Docker 网络,长期更干净的方案是重新规划 Docker address pool,避免它与公司内网、家庭局域网、VPN 和 Tailscale 网段重叠。不过修改已有 Docker 网段可能影响正在运行的容器,因此临时增加精确路由通常风险更低。
让静态路由在 WSL 重启后自动恢复
手动执行 ip route 只在当前 WSL 实例中有效。WSL 重启后路由会消失,可以创建 systemd 服务自动恢复:
1 | # /etc/systemd/system/wsl-lan-route.service |
启用并立即启动:
1 | sudo systemctl daemon-reload |
最后重启 WSL 再验证一次,确保修复不是暂时生效:
1 | wsl --shutdown |
重新进入 WSL 后检查:
1 | ip route get <CLIENT_IP> |
通过 SSH 安全复用服务器本地代理
网络恢复后,不能直接访问外网的内网机器还可以通过 SSH 隧道复用服务器上的本地 HTTP 代理。无需把代理端口直接暴露到整个局域网:
1 | ssh -fNT \ |
然后在客户端设置代理环境变量:
1 | export ALL_PROXY=http://127.0.0.1:<LOCAL_PROXY_PORT> |
验证时不要使用 ping,因为 HTTP 代理不会转发 ICMP。应该使用真实的 HTTP 请求:
1 | curl -I https://github.com |
返回 200 或正常的 301、302 跳转,说明代理链路已经工作。
这种方式有两个好处:代理服务仍然只监听服务器的 127.0.0.1,同时认证和传输都由 SSH 负责,比直接向内网开放代理端口更稳妥。
这次排障得到的经验
排查跨网段访问超时时,可以按下面的顺序进行:
- 确认应用监听的是
0.0.0.0,并在服务器本机访问成功。 - 确认 Windows 当前网络属于预期的 Private 配置文件,入站规则已经匹配。
- 分别从同网段和跨网段客户端测试,判断问题是否只发生在特定来源网段。
- 在 WSL 中执行
ip route get <CLIENT_IP>,检查回包是否被 Docker 网桥截走。 - 使用更精确的静态路由修正回程路径,并通过 systemd 持久化。
- 最后再验证 SSH、Web 服务和 SSH 代理,不要只看端口是否处于监听状态。
这类故障最容易误判为“防火墙还没放开”。端口监听和防火墙只解决请求能否进入服务器,双向通信还要求返回路径正确。只要回程走错网卡,前面的配置看起来都正常,客户端仍然会一直超时。
扩展阅读
- Microsoft Windows 防火墙文档: https://learn.microsoft.com/windows/security/operating-system-security/network-security/windows-firewall/
- Docker 网络文档: https://docs.docker.com/engine/network/
- Linux ip-route 手册: https://man7.org/linux/man-pages/man8/ip-route.8.html
- OpenSSH 端口转发手册: https://man.openbsd.org/ssh#L


