WSL2 服务在 Windows 访问不了?别再瞎试端口转发了:mirrored 与 NAT 模式排查实录
WSL2 服务在 Windows 访问不了?别再瞎试端口转发了
关键词:WSL2 / localhost 访问不了 / mirrored / NAT / .wslconfig / 端口转发
一、先说结论(赶时间看这里)
WSL2 里服务起来了、Windows 却访问不了,八成不是端口或防火墙的问题,而是网络模式(networkingMode)决定了你该用哪个地址访问。
两种模式下的正确访问方式完全相反:
| 模式 | 后端应绑定 | Windows 侧访问方式 |
|---|---|---|
mirrored(镜像) |
0.0.0.0 或 127.0.0.1 均可 |
localhost:端口 ✅ |
NAT(WSL2 传统默认) |
必须 0.0.0.0 |
WSL 的 IP,localhost 通常不通 |
排查第一步永远是查 C:\Users\<用户名>\.wslconfig 里的 networkingMode,而不是改端口转发、关防火墙、改服务监听地址。
二、我遇到的怪事:同一个地址,隔了一晚行为相反
这件事最开始让我怀疑人生。
我在 WSL2 里跑一个 Django 后端,绑 0.0.0.0:8800。前一天晚上,在 Windows 浏览器里用:
http://192.168.1.102:8800
访问得好好的。结果第二天早上,同一个地址超时,curl 直接 exit 28。
更奇怪的是,我随手试了下:
http://localhost:8800
通了。
同一份配置、同一台机器、隔了一晚上,访问方式完全反了过来。
如果你也遇到过"昨天还能用,今天就不行了",或者"网上说用 localhost,我这里死活不通"——很可能就是网络模式在作怪。
三、三步定位法:别一上来就怀疑防火墙
我后来把排查顺序固定成三步,基本能在两分钟内定位:
第 1 步:ping —— 判断网络层通不通
ping <目标地址>
- 通 → 网络层没问题,继续第 2 步
- 不通 → 才是网络/防火墙层面的问题
第 2 步:curl 端口 —— 判断应用层
curl -v http://<目标地址>:8800
Connection refused→ 服务没起来,或绑错了地址timeout(exit 28)→ 网络层不通,或地址用错了模式- 正常返回 → 那问题不在网络
第 3 步:查 .wslconfig —— 这一步最关键
# Windows PowerShell / CMD
type %USERPROFILE%\.wslconfig
看里面有没有:
[wsl2]
networkingMode=mirrored
有 → 镜像模式,用 localhost;没有(或写 nat)→ NAT 模式,用 WSL 的 IP。
我那次的问题就出在这:文件里是 networkingMode=mirrored,而我还按前一天的 NAT 经验去用 IP 访问,自然是超时。
⚠️ 提醒:这个排查顺序不要颠倒。我一开始以为是防火墙或安全组,绕了半天弯路——如果先查
.wslconfig,三十秒就能定位。
四、两种模式的本质差异
NAT 模式(WSL2 传统默认)
WSL2 跑在一个虚拟交换机后面,有自己的内网 IP。Windows 要访问 WSL 里的服务,得走一层转发。
- 服务必须绑
0.0.0.0(绑127.0.0.1的话 Windows 永远访问不到) - Windows 侧用 WSL 的 IP 访问
- 麻烦点:这个 IP 会变(见下一节)
mirrored 模式(镜像,Windows 11 22H2+)
WSL2 直接"镜像"Windows 的网络接口,两者共享网络栈。
- 服务绑
0.0.0.0或127.0.0.1都可以 - Windows 侧直接用
localhost访问 - 优点:不用管 IP、不用配端口转发
- 代价:可能出现端口冲突(Windows 已占用的端口,WSL 里就起不来)
五、一个衍生坑:WSL 的 IP 会漂移
在 NAT 模式下,WSL 的 IP 是动态分配的,重启就变。
我实测过:两天漂了两次,192.168.1.102 → 192.168.124.9。
如果你把 IP 硬编码进前端配置或脚本里,每次漂移都得手动改,非常折腾。
正确做法:别写死 IP。
// vite.config.js
const backendHost = process.env.BACKEND_HOST || 'localhost'
用「环境变量 + localhost 默认值」,两种模式都能兼容,也不用管 IP 漂不漂。
顺带一个建议:多服务并行开发时,端口最好提前错峰约定(比如后端 8800、前端 9090),避免互相踩。
六、延伸:其他几个容易踩的坑(检索补充)
以下是我在排查时从公开资料中检索到的相关问题,不是我本人的第一手经历,列出来供你对照排查时参考:
1. Windows 端口被内核预留(Excluded Port Range)
现象:端口明明没被占用,netstat 也查不到,但服务就是 bind 失败。
# 查看被预留的端口区间(管理员权限)
netsh int ipv4 show excludedportrange protocol=tcp
如果你的目标端口落在某个区间里,换个端口(如 13306、18080)会比重装系统快得多。
2. Docker Desktop 与 mirrored 模式的冲突
有资料指出:WSL 2.4 + Windows 11 24H2 下,mirrored 模式可能与 Docker Desktop 的端口转发机制冲突,表现为"容器内可访问、WSL 内可访问、Windows 宿主机访问不了"。部分用户的解法是切回 NAT 模式。
(这与"推荐用 mirrored 解决 localhost"的说法看似矛盾——其实场景不同:不用 Docker、直接在 WSL 里跑服务时 mirrored 更省事;重度依赖 Docker 端口映射时可能 NAT 更稳。遇到问题时先确认自己的场景,再决定切哪边。)
3. 服务监听地址本身
不同服务的默认监听地址不一样。比如 MySQL 官方镜像默认 bind-address=127.0.0.1,而 Redis 默认 0.0.0.0。
在 WSL 里先确认服务到底监听在哪个地址:
ss -tulpn | grep <端口>
监听在 127.0.0.1 时,NAT 模式下 Windows 是访问不到的。
七、一页纸排查清单
遇到"WSL2 服务访问不了",按顺序过一遍:
| # | 检查项 | 命令 / 位置 | 不通怎么办 |
|---|---|---|---|
| 1 | 服务起来了没 | ss -tulpn \| grep <端口> |
先启动服务 |
| 2 | 监听地址对不对 | 同上,看是 0.0.0.0 还是 127.0.0.1 |
NAT 模式必须 0.0.0.0 |
| 3 | 网络模式是什么 | type %USERPROFILE%\.wslconfig |
这步最关键 |
| 4 | 用对地址没 | mirrored→localhost;NAT→WSL IP |
按模式换地址 |
| 5 | 网络层通不通 | ping <地址> |
不通查防火墙/安全组 |
| 6 | 应用层通不通 | curl -v http://<地址>:<端口> |
看是 refused 还是 timeout |
| 7 | 端口是否被预留 | netsh int ipv4 show excludedportrange protocol=tcp |
换个端口 |
八、写在最后
这类问题的坑在于:它不是"配错了",而是"配对了但用错了访问方式"。
网上关于 WSL2 网络的说法经常互相矛盾——有人说切 mirrored 就好了,有人说 mirrored 会导致 Docker 端口映射失败。两边都没错,只是场景不同。
所以与其记住"该用哪个模式",不如记住这条更通用的经验:
先确认自己处在什么模式,再决定用哪个地址。
查.wslconfig只要三秒钟,比改半小时端口转发划算得多。
本文记录的是本人在 Windows 11 + WSL2 环境下的真实排障过程,所有命令均实测可复现。第六节标注的延伸内容为公开资料检索所得,非本人第一手经历。环境版本不同表现可能有差异,欢迎对照排查。