WSL2 SSH 连接失败排查笔记:Hyper-V 防火墙拦截入站流量

适用环境:Windows 11 + WSL2(Ubuntu 24.04 等发行版),使用 Termius / Xshell 等 SSH 客户端连接 WSL
关键词:WSL2、SSH 超时、Hyper-V 防火墙、systemd socket 激活、localhostForwarding

文中约定:<WSL_IP> 指 WSL 实例的 eth0 地址,<PORT> 指 SSH 端口,示例中分别用 172.30.123.452222 演示。


一、典型症状

SSH 客户端连接 WSL 中的 Linux 发行版时失败:

Connecting to "<WSL_IP>" port "<PORT>"
Connection failed: connection timed out. No more addresses to try.

关键特征:

  • 之前一直正常,突然连不上
  • 报错是 connection timed out(超时),而不是 connection refused(拒绝)
  • wsl -d <发行版名> 可以正常进入系统

经验法则:超时 vs 拒绝

  • 超时(timed out):数据包被防火墙静默丢弃(DROP),排查方向是防火墙
  • 拒绝(refused):端口没有进程监听,排查方向是服务没启动

分清这两种报错,能省掉一半排查时间。


二、背景知识:WSL2 的网络模型

排查前需要先理解 WSL2 网络的三件事:

1. NAT 架构

WSL2 运行在一个轻量级 Hyper-V 虚拟机中,通过虚拟交换机做 NAT:

  • 宿主机上出现一张虚拟网卡 vEthernet (WSL),作为 WSL 网段的网关
  • WSL 实例的 eth0 获得一个 172.x.x.x 网段的地址(每次重启 WSL 可能变化)

2. localhostForwarding

WSL2 默认开启 localhost 转发:在 Windows 上访问 127.0.0.1:<PORT>,会被转发到 WSL 内部监听的对应端口。这条通道不经过虚拟交换机的入站过滤

3. 多发行版共享网络命名空间

所有 WSL2 发行版跑在同一台虚拟机里,共享同一个网络命名空间(eth0 的 MAC 和 IP 完全相同)。由此带来一个实践技巧:

  • 多个发行版都开 SSH 时,要用不同端口区分(例如 Ubuntu 用 2222,另一个发行版用 2211)
  • 在任意一个发行版里执行 ss -tlnp,能看到所有发行版监听的端口

三、排查步骤

第 1 步:核对客户端配置与服务端端口

进入目标发行版,确认 sshd 实际配置的端口与客户端填写的一致:

wsl -l -v                        # 确认目标发行版是 Running 状态
wsl -d <发行版名>
grep -E '^Port' /etc/ssh/sshd_config

如果 wsl -l -v 显示发行版是 Stopped,它监听的端口自然不通,启动发行版即可。

第 2 步:确认 WSL 内部服务正常

在 WSL 发行版内执行:

systemctl status ssh ssh.socket --no-pager
ss -tlnp

正常的输出类似:

○ ssh.service - OpenBSD Secure Shell server
     Active: inactive (dead)        <-- socket 激活模式下这是正常的!
TriggeredBy: ● ssh.socket

● ssh.socket - OpenBSD Secure Shell server socket
     Active: active (listening)
    Listen: 0.0.0.0:2222 (Stream)

ss -tlnp 中应能看到:

LISTEN 0 8192 0.0.0.0:2222 0.0.0.0:* users:(("systemd",pid=1,...))

如果端口没有监听,分支处理:

  • 服务没启动systemctl restart ssh,并 systemctl enable ssh 设置自启

  • systemctl 报错(未以 systemd 启动):在 /etc/wsl.conf 写入以下内容,然后 wsl --shutdown 重启:

    [boot]
    systemd=true
    

第 3 步:Windows 侧连通性对比测试(定位的关键)

在 Windows PowerShell 中分别测试两条路径:

Test-NetConnection 127.0.0.1 -Port 2222        # 路径一:localhost 转发
Test-NetConnection 172.30.123.45 -Port 2222    # 路径二:直连 WSL IP(换成实际地址)

结果组合的含义:

127.0.0.1 WSL_IP 结论
✅ 通 ✅ 通 服务正常,检查客户端配置
✅ 通 ❌ 不通 宿主机到 WSL 的链路被过滤 → 第 4 步
❌ 不通 ❌ 不通 localhostForwarding 异常,wsl --shutdown 重启 WSL 试试

典型的"被过滤"输出长这样——ping 通但 TCP 不通

PingSucceeded          : True     <-- 链路正常
TcpTestSucceeded       : False    <-- TCP 被防火墙丢弃

此时可以留意一下网卡名:

Get-NetAdapter | Where-Object Name -like '*WSL*'
# vEthernet (WSL (Hyper-V firewall))   <-- 名字里直接写着防火墙

第 4 步:检查 Hyper-V 防火墙

新版 Windows 11 给 Hyper-V 虚拟交换机引入了独立的防火墙,WSL 的交换机同样受其管控,默认拦截入站流量。查询策略(WSL 交换机的 GUID 是固定的):

Get-NetFirewallHyperVVMSetting -PolicyStore ActiveStore -Name '{40E0AC32-46A5-438A-A0B2-2B479E8F2E90}' |
  Select-Object Enabled, DefaultInboundAction, DefaultOutboundAction

如果看到:

Enabled DefaultInboundAction DefaultOutboundAction
------- -------------------- ---------------------
   True                Block                 Allow

这就是根因。出站 Allow、入站 Block 的组合很有迷惑性:WSL 里上网、装软件一切正常,只有"从外面连进来"会全部超时。

第 5 步:修复并验证

① 放行入站流量(管理员 PowerShell):

Set-NetFirewallHyperVVMSetting -Name '{40E0AC32-46A5-438A-A0B2-2B479E8F2E90}' -DefaultInboundAction Allow

② 重启 WSL 使配置生效(必须!)

配置变更不会热加载到正在运行的 WSL 实例,必须重启:

wsl --shutdown
# 等待约 10 秒
wsl -d <发行版名>

⚠️ wsl --shutdown 会停掉 WSL 内所有服务。systemd 管理且已 enable 的服务会自动恢复,手动启动的进程需要重新拉起。

③ 验证

Test-NetConnection 172.30.123.45 -Port 2222
# TcpTestSucceeded : True ✅

该设置为持久化配置,重启 Windows 后依然有效。


四、根因图解

flowchart LR subgraph WIN["Windows 11 宿主机"] T["SSH 客户端"] FW["Hyper-V 防火墙<br/>DefaultInboundAction: Block"] VA["vEthernet (WSL)<br/>虚拟交换机网关"] end subgraph VM["WSL2 虚拟机"] SK["ssh.socket / sshd<br/>监听 :2222"] D1["发行版 A"] D2["发行版 B :2211"] end T -->|"路径一 127.0.0.1:2222<br/>localhostForwarding 不受影响"| SK T -->|"路径二 直连 WSL IP"| FW FW -->|"Block 时 TCP 被静默丢弃"| VA VA --> SK

总结根因链条:

  1. Windows 更新或配置变更后,WSL 虚拟交换机被挂上 Hyper-V 防火墙,默认入站策略为 Block
  2. 宿主机直连 WSL IP 的 TCP 包被静默丢弃 → 客户端表现为超时(ICMP ping 不受此策略影响,所以 ping 通)
  3. 127.0.0.1 走 localhostForwarding 通道,不经过该防火墙,因此一直可用
  4. 修改防火墙策略后必须重启 WSL,运行中的实例不会热加载新配置

五、知识点:Ubuntu 24.04 的 systemd socket 激活

Ubuntu 24.04 的 SSH 默认改为 socket 激活模式,与传统服务模型有区别:

  • ssh.socket 常驻监听端口(ss -tlnp 里显示持有者是 systemd
  • ssh.service 平时处于 inactive (dead),有连接进来时才被拉起——这不是故障

由此产生一个常见的坑:修改 sshd_config 中的 Port 后,配置不会自动生效,必须重新生成 socket 配置:

systemctl daemon-reload
systemctl restart ssh.socket
ss -tlnp | grep <新端口>   # 验证新端口已监听

只改配置不重启 socket 的话,sshd 实际仍监听在旧端口上。


六、通用排查流程图

flowchart TD A["SSH 连接 WSL 失败"] --> B{"报错类型?"} B -->|"connection refused"| C["端口无监听<br/>检查 sshd 是否启动、发行版是否 Stopped"] B -->|"connection timed out"| D["WSL 内执行 ss -tlnp<br/>端口在监听吗?"] D -->|"否"| E["启动 ssh 服务<br/>或检查 ssh.socket / systemd"] D -->|"是"| F["Test-NetConnection 127.0.0.1 -Port 端口"] F -->|"不通"| G["localhostForwarding 异常<br/>wsl --shutdown 重启"] F -->|"通"| H["Test-NetConnection WSL_IP -Port 端口"] H -->|"通"| I["服务已恢复<br/>检查客户端地址和端口配置"] H -->|"不通"| J["查 Hyper-V 防火墙<br/>DefaultInboundAction"] J --> K["Set 为 Allow<br/>然后 wsl --shutdown"]

七、速查命令表

场景 命令
查看 WSL 发行版及状态 wsl -l -v
查看端口监听情况(WSL 内) ss -tlnp
查看 ssh 服务/socket 状态(WSL 内) systemctl status ssh ssh.socket --no-pager
改完 sshd 端口后生效(Ubuntu 24.04) systemctl daemon-reload && systemctl restart ssh.socket
启用 systemd(WSL 内 /etc/wsl.conf [boot] 下加 systemd=true
测试 localhost 转发通道 Test-NetConnection 127.0.0.1 -Port <PORT>
测试直连 WSL IP Test-NetConnection <WSL_IP> -Port <PORT>
查 Hyper-V 防火墙策略 Get-NetFirewallHyperVVMSetting -PolicyStore ActiveStore -Name '{40E0AC32-46A5-438A-A0B2-2B479E8F2E90}'
放行入站(管理员) Set-NetFirewallHyperVVMSetting -Name '{40E0AC32-46A5-438A-A0B2-2B479E8F2E90}' -DefaultInboundAction Allow
查显式防火墙规则 Get-NetFirewallHyperVRule -PolicyStore ActiveStore
重启 WSL wsl --shutdown

八、经验总结与最佳实践

  1. 超时想防火墙,拒绝想服务:先看报错类型再定排查方向。
  2. ping 通 + TCP 不通 = 防火墙:链路层正常、传输层被过滤,是防火墙的典型特征。
  3. SSH 客户端固定用 127.0.0.1:<PORT>:走 localhostForwarding,不经过 Hyper-V 防火墙,也不受 WSL IP 漂移影响(WSL 重启后 IP 可能变化),是最稳的连法。
  4. 多发行版用不同 SSH 端口区分:WSL2 共享网络栈,任一发行版内 ss -tlnp 可看全局。
  5. Ubuntu 24.04 改 SSH 端口:改完配置必须 daemon-reload + 重启 ssh.socket,否则仍监听旧端口。
  6. 改 Hyper-V 防火墙策略后必须 wsl --shutdown:运行中的实例不热加载新策略。
  7. 安全姿势:日常保持 DefaultInboundAction: Block + 用 127.0.0.1 连接;仅当局域网其他机器需要访问 WSL 服务时才放行入站。
posted @ 2026-07-17 11:43  RK5123153  阅读(80)  评论(0)    收藏  举报