记录WSL2中GitLab端口访问错误问题之因一

问题现象

在 Windows 宿主机上通过 WSL2 运行 GitLab,配置如下:

  • WSL2 内网 IP:172.26.25.30
  • GitLab 监听端口:8765
  • 宿主机物理网卡 IP:192.168.1.36

症状:

  • ✅ 访问 http://172.26.25.30:8765 正常GitLab 页面打开
  • ❌ 访问 http://192.168.1.36:8765 拒绝连接

排查过程

第一步:确认 GitLab 服务状态

在 WSL2 内执行:

(base) zth@WIN-PJI56QR0O5M:~$ sudo gitlab-ctl status
[sudo] password for zth:
run: alertmanager: (pid 452) 16s; run: log: (pid 446) 16s
run: gitaly: (pid 441) 16s; run: log: (pid 435) 16s
run: gitlab-exporter: (pid 439) 16s; run: log: (pid 425) 16s
run: gitlab-kas: (pid 429) 16s; run: log: (pid 421) 16s
run: gitlab-workhorse: (pid 440) 16s; run: log: (pid 433) 16s
run: logrotate: (pid 434) 16s; run: log: (pid 430) 16s
run: nginx: (pid 431) 16s; run: log: (pid 426) 16s
run: node-exporter: (pid 420) 16s; run: log: (pid 416) 16s
run: postgres-exporter: (pid 428) 16s; run: log: (pid 423) 16s
run: postgresql: (pid 437) 16s; run: log: (pid 432) 16s
run: puma: (pid 436) 16s; run: log: (pid 417) 16s
run: redis: (pid 422) 16s; run: log: (pid 419) 16s
run: redis-exporter: (pid 438) 16s; run: log: (pid 427) 16s
run: sidekiq: (pid 424) 16s; run: log: (pid 415) 16s
# 所有组件均为 run 状态
sudo netstat -tlnp | grep 8765
# 显示 nginx 监听 0.0.0.0:8765
curl -I http://localhost:8765
# 返回 200 OK

GitLab 自身正常工作。

第二步:检查 Windows 端口转发

Windows 中用于将宿主机端口转发到 WSL2 的常用命令是 netsh interface portproxy

查看已有规则:

PS C:\Users\Administrator> netsh interface portproxy show all

侦听 ipv4:                 连接到 ipv4:

地址            端口        地址            端口
--------------- ----------  --------------- ----------
0.0.0.0         8080        172.26.25.30    80

输出显示只有 8080 -> 172.26.25.30:80 的转发,没有 8765。于是添加规则:

netsh interface portproxy add v4tov4 listenport=8765 listenaddress=0.0.0.0 connectport=8765 connectaddress=172.26.25.30

再次查看 portproxy 规则已存在,但 netstat -ano | findstr :8765 却没有 LISTENING 状态。端口转发规则没有生效!192.168.1.36:8765仍不可访问。

第三步:发现"端口排除"(Port Exclusion)

执行命令查看被系统保留的端口范围:

netsh int ipv4 show excludedportrange protocol=tcp

输出显示:

开始端口    结束端口
----------    --------
        80          80
      5357        5357
      8566        8665
      8666        8765   ⚠️ 8765 被包含在排除区间内
      8766        8865
      ...

结论:端口 8765 被 Windows 系统保留(Hyper-V / WSL2 相关),任何普通程序都无法绑定该端口,包括 portproxy。

什么是端口排除?为什么要有这个机制?

端口排除(Port Exclusion)是 Windows 的一种保护机制。为了保障 Hyper-V、WSL2、Windows 沙盒等底层网络组件的稳定运行,系统会动态预留一段 TCP/UDP 端口范围。这些端口不供普通应用程序使用,以避免冲突。

常见端口排除范围示例:8566~9365,并且每次重启可能变化。如果你的服务恰好落在该范围内,就会遇到"无法监听"的问题。

解决办法

方法一:从排除列表删除指定端口

核心思路:将 8765 端口从排除列表中移除。

步骤:

  1. 以管理员身份打开 PowerShell
  2. 停止 Windows NAT 驱动服务
    net stop winnat
  3. 删除端口排除
    netsh int ipv4 delete excludedportrange protocol=tcp startport=8765 numberofports=1
  4. 重新启动 winnat
    net start winnat
  5. 验证删除成功
    netsh int ipv4 show excludedportrange protocol=tcp

    输出中不应再包含 8765 或 8666-8765 范围。

  6. 重新添加 portproxy 规则
    netsh interface portproxy delete v4tov4 listenport=8765 listenaddress=0.0.0.0   # 先删除旧规则
    netsh interface portproxy add v4tov4 listenport=8765 listenaddress=0.0.0.0 connectport=8765 connectaddress=172.26.25.30
  7. 检查监听状态
    netstat -ano | findstr :8765

    应出现 TCP 0.0.0.0:8765 ... LISTENING

方法二:修改动态端口范围

如果不想单独处理某个端口,可以将动态端口起始值调高,避开常用端口:

netsh int ipv4 set dynamicport tcp start=40000 num=25535
net stop winnat && net start winnat

方法三:换一个未被排除的端口

例如 8081、9090 等,修改 GitLab 的 external_url 并更新 portproxy 规则。适合临时或测试环境。

解决最后的"拒绝连接":Windows 防火墙

完成上述操作后,portproxy 已正常监听 0.0.0.0:8765,但 Test-NetConnection 192.168.1.36 -Port 8765 仍然失败。原因是 Windows 防火墙阻止了通过物理网卡 IP 的入站连接(即使本地访问)。

解决办法:添加防火墙入站规则

New-NetFirewallRule -DisplayName "Allow GitLab 8765" -Direction Inbound -LocalPort 8765 -Protocol TCP -Action Allow

或者临时关闭防火墙测试:

Set-NetFirewallProfile -All -Enabled False
# 测试成功后重新开启
Set-NetFirewallProfile -All -Enabled True

验证连通性

Test-NetConnection 192.168.1.36 -Port 8765

期望输出 TcpTestSucceeded : True

  • http://192.168.1.36:8765 成功打开 GitLab
  • http://localhost:8765 同样正常
  • ✅ 局域网内其他设备也可通过 http://192.168.1.36:8765 访问

总结

  • WSL2 网络透明性:直接使用 WSL2 IP 访问是可行的,但若需要通过宿主机物理 IP 访问,则需要 portproxy + 防火墙放行。
  • 端口排除是隐形坑:当 portproxy 规则添加后却不监听时,优先检查排除端口范围。
  • Windows 防火墙拦截本地回环外的 IP:即使源和目标都是本机,防火墙仍会拦截非 127.0.0.1 的流量,必须显式放行。
  • 推荐长期方法:使用 WSL2 的镜像网络模式(networkingMode=mirrored)可彻底避免端口转发和排除问题,但需要较新版本的 Windows 11。

命令速查

# 查看端口排除范围
netsh int ipv4 show excludedportrange protocol=tcp

# 删除指定端口排除
netsh int ipv4 delete excludedportrange protocol=tcp startport=8765 numberofports=1

# 管理 portproxy 规则
netsh interface portproxy show all
netsh interface portproxy add v4tov4 listenport=8765 listenaddress=0.0.0.0 connectport=8765 connectaddress=172.26.25.30

# 防火墙规则
New-NetFirewallRule -DisplayName "RuleName" -Direction Inbound -LocalPort 8765 -Protocol TCP -Action Allow