Windows 11 + WSL2 + Docker Desktop 端口无法访问问题完整排查与解决

6 阅读3分钟

Windows 11 + WSL2 + Docker Desktop 端口无法访问问题完整排查与解决

关键词:Windows 11 24H2 / WSL 2.4.x / Docker Desktop / localhost 访问失败 / 端口映射 / mirrored networking / NAT / Excluded Port Range


一、问题背景

Windows 11(24H2)+ WSL2 + Docker Desktop 的开发环境中,启动容器后经常会遇到一种非常“反直觉”的问题:

  • 容器内可以访问服务(如 Nginx / MySQL / Redis)
  • WSL 终端中可以访问服务
  • Windows 宿主机(CMD / PowerShell / 浏览器)无法访问

即使已经正确配置了 Docker 的 -pports: 端口映射,问题依旧存在。

本文将完整记录一次从现象 → 原因 → 系统级根因 → 最终解决方案的排查过程。


二、典型环境

Windows 版本: 10.0.26100.x (Windows 11 24H2)
WSL 版本: 2.4.13.0
Linux Kernel: 5.15.x
Docker Desktop: 4.55.0

三、典型错误现象

1. Nginx

docker run -d --name nginx-web -p 8085:80 nginx
  • 容器内:curl localhost
  • WSL 中:curl localhost:8085
  • Windows 浏览器:http://localhost:8085 ❌(无法访问)

2. MySQL

ports:
  - "3306:3306"
  • 容器内 MySQL 正常启动
  • Windows 无法 telnet / 连接 3306

四、第一层根因:WSL 2.4 的 mirrored networking

1. 问题根源

WSL 2.4 + Windows 11 24H2 中,WSL 默认启用了 mirrored networking(镜像网络)

该模式下:

  • WSL 与 Windows 共用网络栈
  • Docker Desktop 的端口转发机制无法正确工作
  • 表现为:WSL 可访问,Windows localhost 不可访问

这是当前 Docker Desktop 与 WSL 新网络栈之间的已知不兼容问题。


2. 正确解决方式:强制切回 NAT

编辑(或创建)文件:

C:\Users<用户名>.wslconfig

推荐配置如下:

[wsl2]
networkingMode=nat
localhostForwarding=true

[experimental]
autoMemoryReclaim=gradual

然后严格按顺序重启

wsl --shutdown
  1. 完全退出 Docker Desktop
  2. 重新启动 Docker Desktop (以管理员身份启动)
  3. 再启动 WSL

此时:

  • Windows localhost 访问 Docker 容器端口恢复正常

五、WSL 启动时的提示说明(非错误)

wsl: 检测到 localhost 代理配置,但未镜像到 WSL。
NAT 模式下的 WSL 不支持 localhost 代理。

解释:

  • Windows 中存在代理配置(HTTP / SOCKS / PAC)
  • NAT 模式下 WSL 不会继承 localhost 代理
  • 不影响 Docker 端口映射与服务访问

如需消除提示,确保 .wslconfig 中未启用:

autoProxy=true

六、第二层根因:为什么 MySQL 不像 Redis 那样“自动可访问”?

1. 关键事实

Docker 只负责端口转发,不负责服务监听地址。

是否显示 0.0.0.0:端口,取决于容器内服务本身监听在哪个地址

服务默认监听
Redis0.0.0.0:6379
MySQL127.0.0.1:3306

2. MySQL 的安全设计

MySQL 官方镜像默认:

bind-address = 127.0.0.1

这是出于安全考虑,防止数据库被意外暴露。

3. 正确的 MySQL 启动方式

docker-compose 示例(推荐)
services:
  mysql:
    image: mysql:latest
    ports:
      - "13306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: 123456
      MYSQL_ROOT_HOST: "%"
    command:
      --bind-address=0.0.0.0

七、最终隐藏大坑:Windows Excluded Port Range

1. 现象

即使:

  • 没有任何进程占用 3306
  • netstat 查不到

Docker 仍然报错:

listen tcp 0.0.0.0:3306: bind: An attempt was made to access a socket in a way forbidden by its access permissions

2. 真正原因

3306 被 Windows 内核预留(Excluded Port Range)

验证方式(管理员 CMD):

netsh int ipv4 show excludedportrange protocol=tcp

只要 3306 落在某个区间内:

  • ❌ 无法 bind
  • ❌ netstat 看不到
  • ❌ Docker / MySQL 无解

八、最终结论与最佳实践

1. 不要再执着于 3306

在 Windows + Docker 环境中,推荐:

服务宿主机端口
MySQL13306 / 23306
Redis16379
Nginx18080 / 808x

2. 核心总结

  • ❌ 不是 Docker 配错
  • ❌ 不是 MySQL / Nginx 的锅
  • ❌ 不是 WSL 使用姿势问题
  • ✅ 是 WSL 新网络栈 + Windows 内核端口策略 + Docker Desktop 适配问题的叠加结果

九、一句话总结

真他妈的操蛋


本文适用于:Windows 11 + WSL2 + Docker Desktop 开发环境排错参考