记录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:8765curl -I http://localhost:8765
# 返回 200 OKGitLab 自身正常工作。
第二步:检查 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 端口从排除列表中移除。
步骤:
- 以管理员身份打开 PowerShell
- 停止 Windows NAT 驱动服务
net stop winnat - 删除端口排除
netsh int ipv4 delete excludedportrange protocol=tcp startport=8765 numberofports=1 - 重新启动 winnat
net start winnat - 验证删除成功
netsh int ipv4 show excludedportrange protocol=tcp输出中不应再包含 8765 或 8666-8765 范围。
- 重新添加 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 - 检查监听状态
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