局域网访问WSL服务——问题排查笔记

给团队做了一个RAG项目,由于使用的向量数据库是milvus(不支持Windows),以及方便后面项目迁移到服务器,遂开发调试过程中使用的是WSL2。项目在本机上开发调试结束后,由于是给团队使用的,需要局域网内其它设备能够访问这个运行在WSL2上的服务。
这次的排查经历相对比较完整,可以作为以后参考的排查清单。

目标: 允许局域网内的其他设备访问运行在 WSL 内部的服务。

初始环境:
Windows 主机 IP (WLAN): 10.52.85.154
WSL 实例 IP: 172.21.156.148
服务端口: 前端 3000,后端 8001
问题现象: 无法从局域网其他设备通过http://10.52.85.154:3000访问WSL中的服务。

下面是这次的问题排查过程:

1. 检查 Windows 端口转发 (netsh) 配置

  • 目的: 确认是否有将 Windows 主机端口流量转发到 WSL IP 端口的规则。
  • 操作 (Windows PowerShell/CMD):
    netsh interface portproxy show all
    
  • 结果:
        侦听 ipv4:                 连接到 ipv4:
    地址            端口        地址            端口
    --------------- ----------  --------------- ----------
    0.0.0.0         8001        172.21.156.148  8001
    0.0.0.0         3000        172.21.156.148  3000
    
  • 分析: 存在将 0.0.0.0:3000 (所有 IPv4 地址的 3000 端口) 转发到 172.21.156.148:3000 的规则。规则本身看起来没问题,但访问仍然失败,说明问题可能在其他环节。

2. 检查 Windows 防火墙

  • 目的: 确认 Windows 防火墙是否阻止了外部对 3000 端口的访问。
  • 操作 (Windows PowerShell - 管理员):
    New-NetFirewallRule -DisplayName "Allow WSL Port 3000" -Direction Inbound -LocalPort 3000 -Protocol TCP -Action Allow
    
  • 结果: 添加规则后,从局域网访问 http://10.52.85.154:3000 仍然失败。
  • 分析: 问题不在于 Windows 防火墙缺少基本的入站规则。

3. 检查 WSL 内部服务监听地址

  • 目的: 确认 WSL 内的服务是否监听在 0.0.0.0 (所有地址) 或 WSL 的具体 IP 上,而不是仅监听 127.0.0.1 (localhost)。
  • 操作 (WSL 终端):
    ss -tulnp | grep 3000
    
  • 结果:
    tcp   LISTEN 0      511          0.0.0.0:3000       0.0.0.0:*    users:(("node",pid=10936,fd=29))
    
  • 分析: 服务正确监听在 0.0.0.0:3000,可以接受来自任何 IP 的连接(包括从 Windows 转发过来的)。

4. 检查 WSL 内部防火墙 (ufw)

  • 目的: 确认 WSL 发行版内部的防火墙是否阻止了连接。
  • 操作 (WSL 终端):
    sudo ufw status
    
  • 结果:
    sudo: ufw: command not found
    
  • 分析: WSL 内部没有运行 ufw 防火墙。

5. 检查第三方安全软件

  • 目的: 确认 Windows 主机上的第三方防病毒/安全软件是否干扰了连接。
  • 操作: 暂时禁用相关软件的防火墙或网络防护功能。
  • 结果: 问题依旧。

6. 本地连接测试 (关键转折点)

  • 目的: 精确定位是 Windows -> WSL 连接问题,还是 Windows -> 局域网问题,还是 netsh 规则本身的问题。
  • 操作 (Windows PowerShell/CMD):
    1. curl http://172.21.156.148:3000 (Windows -> WSL IP)
    2. curl http://localhost:3000 (Windows -> localhost -> 转发 -> WSL)
    3. curl http://10.52.85.154:3000 (Windows -> Host LAN IP -> 转发 -> WSL)
  • 结果:
    1. 成功 (StatusCode: 200):WSL 服务本身正常,且可从 Windows 直接访问。
    2. 成功 (StatusCode: 200):netsh 端口转发对 localhost 流量有效。
    3. 失败 (无法连接到远程服务器):netsh 端口转发对主机自身局域网 IP 的流量无效,即使请求来自本机。
  • 分析: 问题锁定在 Windows 处理指向自身外部 IP 地址 (10.52.85.154) 的端口转发时的行为异常 (可能与网络堆栈或 “Hairpin NAT” 有关),即使 netsh 规则监听的是 0.0.0.0。

7. 修正 netsh 规则 (使用具体 IP)

  • 目的: 尝试通过显式绑定 netsh 监听主机的具体局域网 IP 来解决上述问题。
  • 操作 (Windows PowerShell - 管理员):
    # 删除旧规则
    netsh interface portproxy delete v4tov4 listenport=3000 listenaddress=0.0.0.0
    # 添加新规则
    netsh interface portproxy add v4tov4 listenport=3000 listenaddress=10.52.85.154 connectport=3000 connectaddress=172.21.156.148
    
  • 结果:
    在 Windows 主机上 curl http://10.52.85.154:3000 成功。
    新问题出现: 从局域网其他设备访问 http://10.52.85.154:3000,前端页面可以加载,但前端无法连接后端 API。

8. 诊断前端与后端连接问题

  • 获取信息:
    • 后端启动命令: uvicorn main:app --reload --port 8001 --host 0.0.0.0 (确认后端在 WSL 的 8001 端口)
    • 前端相关配置
    • 局域网客户端浏览器开发者工具报错: ERR_CONNECTION_REFUSED,尝试连接 localhost:8001
  • 分析:
    • 前端代码(运行在客户端浏览器)错误地将后端 API 地址硬编码或配置为了 localhost:8001。当在局域网其他设备上运行时,localhost 指向该设备自身,而非运行后端的 Windows 主机。

9. 最终解决方案

步骤 1: 修改前端代码中的 API 地址

  • 目的: 让前端代码请求正确的后端地址。
  • 操作: 查找前端项目中配置或调用后端 API 的地方,将地址从http://localhost:8001修改为 Windows 主机的 IP 和后端端口: http://10.52.85.154:8001,也可直接配置环境变量。

步骤 2: 修正 netsh 规则 for 8001 端口

  • 目的: 解决后端端口 (8001) 可能存在的与 3000 端口相同的本机 IP 访问问题,并确保外部访问转发。
  • 操作 (Windows PowerShell - 管理员):
    netsh interface portproxy delete v4tov4 listenport=8001 listenaddress=0.0.0.0
    netsh interface portproxy add v4tov4 listenport=8001 listenaddress=10.52.85.154 connectport=8001 connectaddress=172.21.156.148
    

步骤 3: 添加 Windows 防火墙规则 for 8001 端口

  • 目的: 允许外部设备访问 Windows 主机的 8001 端口。
  • 操作 (Windows PowerShell - 管理员):
    New-NetFirewallRule -DisplayName "Allow WSL Port 8001" -Direction Inbound -LocalPort 8001 -Protocol TCP -Action Allow
    

最终结果:
从局域网其他设备访问http://10.52.85.154:3000,前端加载正常,并且前端可以成功调用位于http://10.52.85.154:8001的后端 API。问题解决。

关键总结:

  • 端口转发 (netsh): 虽然监听 0.0.0.0 理论上可行,但在 WSL 场景下,当通过主机自身外部 IP 访问时可能出现问题。显式将 listenaddress 设置为主机的局域网 IP (10.52.85.154) 是更可靠的方案。
  • 防火墙: 必须确保 Windows 防火墙 (以及可能的第三方安全软件) 允许外部访问所需端口 (本例中为 3000 和 8001)。
  • 服务监听: 确保 WSL 内的服务监听在 0.0.0.0 或其分配的 IP 上。
  • 前端配置: 客户端 (浏览器) 运行的前端代码必须使用服务器的可访问 IP 地址 (本例中为 10.52.85.154) 和正确端口来调用后端 API,而不是 localhost 或 WSL 内部 IP。

你可能感兴趣的:(linux,windows)