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.45和2222演示。
一、典型症状
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 后依然有效。
四、根因图解
总结根因链条:
- Windows 更新或配置变更后,WSL 虚拟交换机被挂上 Hyper-V 防火墙,默认入站策略为 Block
- 宿主机直连 WSL IP 的 TCP 包被静默丢弃 → 客户端表现为超时(ICMP ping 不受此策略影响,所以 ping 通)
127.0.0.1走 localhostForwarding 通道,不经过该防火墙,因此一直可用- 修改防火墙策略后必须重启 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 实际仍监听在旧端口上。
六、通用排查流程图
七、速查命令表
| 场景 | 命令 |
|---|---|
| 查看 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 |
八、经验总结与最佳实践
- 超时想防火墙,拒绝想服务:先看报错类型再定排查方向。
- ping 通 + TCP 不通 = 防火墙:链路层正常、传输层被过滤,是防火墙的典型特征。
- SSH 客户端固定用
127.0.0.1:<PORT>:走 localhostForwarding,不经过 Hyper-V 防火墙,也不受 WSL IP 漂移影响(WSL 重启后 IP 可能变化),是最稳的连法。 - 多发行版用不同 SSH 端口区分:WSL2 共享网络栈,任一发行版内
ss -tlnp可看全局。 - Ubuntu 24.04 改 SSH 端口:改完配置必须
daemon-reload+ 重启ssh.socket,否则仍监听旧端口。 - 改 Hyper-V 防火墙策略后必须
wsl --shutdown:运行中的实例不热加载新策略。 - 安全姿势:日常保持
DefaultInboundAction: Block+ 用 127.0.0.1 连接;仅当局域网其他机器需要访问 WSL 服务时才放行入站。

浙公网安备 33010602011771号