W weiserv
← 返回博客

WSL2 服务在 Windows 访问不了?别再瞎试端口转发了:mirrored 与 NAT 模式排查实录

WSL2 服务在 Windows 访问不了?别再瞎试端口转发了

关键词:WSL2 / localhost 访问不了 / mirrored / NAT / .wslconfig / 端口转发

一、先说结论(赶时间看这里)

WSL2 里服务起来了、Windows 却访问不了,八成不是端口或防火墙的问题,而是网络模式(networkingMode)决定了你该用哪个地址访问

两种模式下的正确访问方式完全相反

模式 后端应绑定 Windows 侧访问方式
mirrored(镜像) 0.0.0.0127.0.0.1 均可 localhost:端口
NAT(WSL2 传统默认) 必须 0.0.0.0 WSL 的 IPlocalhost 通常不通

排查第一步永远是查 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.0127.0.0.1 都可以
  • Windows 侧直接用 localhost 访问
  • 优点:不用管 IP、不用配端口转发
  • 代价:可能出现端口冲突(Windows 已占用的端口,WSL 里就起不来)

五、一个衍生坑:WSL 的 IP 会漂移

在 NAT 模式下,WSL 的 IP 是动态分配的,重启就变

我实测过:两天漂了两次,192.168.1.102192.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 环境下的真实排障过程,所有命令均实测可复现。第六节标注的延伸内容为公开资料检索所得,非本人第一手经历。环境版本不同表现可能有差异,欢迎对照排查。

广告位占位 · post-inline