WSL2 中 Docker 部署的 SearXNG 在 Windows 无法通过 localhost 访问的排查与解决
日期: 2026-05-29
环境: Windows 11 (10.0.26200.8457) + WSL2 2.5.7.0 + Docker (Linux 原生,非 Docker Desktop)
1. 问题描述
在 WSL2 的 Docker 容器中部署了 SearXNG 搜索引擎服务,WSL2 内部访问正常,但 Windows 浏览器访问 http://localhost:8888 无法打开页面。
现象
| 测试方式 | 结果 |
|---|---|
WSL2 内: curl http://127.0.0.1:8888 |
✅ HTTP 200 |
Windows: curl.exe http://localhost:8888 |
❌ exit code 7(连接拒绝) |
Windows: curl.exe http://172.18.14.110:8080 |
✅ HTTP 200 |
2. 根因分析
问题的核心是 WSL2 网络模式与 Docker 网络模式的组合导致端口未映射到 Windows localhost,由以下三个因素叠加造成:
2.1 .wslconfig 格式错误 → mirrored 模式未生效
用户配置了 networkingMode=mirrored(该模式会让 WSL2 与 Windows 共享网络栈,localhost 互通),但 .wslconfig 文件缺少必需的 [wsl2] section header:
错误的配置:
ini
networkingMode=mirrored
autoProxy=true
正确的配置:
ini
[wsl2]
networkingMode=mirrored
autoProxy=true
文件位置:
C:\Users\<用户名>\.wslconfig
没有 [wsl2] section header,WSL2 启动时忽略所有配置项,回退到默认的 NAT 模式。在 NAT 模式下,WSL2 拥有独立的虚拟网卡和 IP 地址,Windows 的 localhost 不会自动路由到 WSL2。
2.2 Docker 使用 bridge 网络 + docker-proxy 端口转发
原始容器创建命令使用了 Docker 默认的 bridge 网络模式:
bash
docker run -d --name searxng -p 8888:8080 ... ghcr.io/searxng/searxng:latest
-p 8888:8080 的含义:
- 容器内 granian 监听 8080 端口
docker-proxy进程在 WSL2 的0.0.0.0:8888上监听并转发
关键点 :docker-proxy 绑定在 WSL2 的网络命名空间 内,而非 Windows 的网络栈。在 NAT 模式下,Windows localhost 不会自动转发到 WSL2 的端口。
2.3 SearXNG 端口配置的坑
SearXNG 镜像内部通过环境变量 GRANIAN_PORT=8080 指定监听端口。即使 settings.yml 中配置了 port: 8888,实际监听端口仍由 GRANIAN_PORT 环境变量决定(默认 8080)。这导致:
-p 8888:8080→ Windows 期望 8888,容器实际监听 8080,映射关系正确- 改用
--network host后,容器直接使用 WSL2 网络栈,SearXNG 监听 8080(非 8888)
3. 网络架构图
NAT 模式(当前实际状态)
┌─────────────────────────────────────────────┐
│ Windows │
│ localhost:8888 ← ❌ 无路由 │
│ 172.18.14.110:8080 ← ✅ 可达 │
│ │
│ ┌───────────────────────────────────────┐ │
│ │ WSL2 (NAT, IP: 172.18.14.110) │ │
│ │ │ │
│ │ ┌─────────────────────────────────┐ │ │
│ │ │ Docker bridge network │ │ │
│ │ │ container IP: 172.17.0.x │ │ │
│ │ │ granian → :8080 │ │ │
│ │ └─────────────────────────────────┘ │ │
│ │ ↕ docker-proxy │ │
│ │ 0.0.0.0:8888 (WSL2 命名空间) │ │
│ └───────────────────────────────────────┘ │
└─────────────────────────────────────────────┘
Mirrored 模式(修复后)
┌─────────────────────────────────────────────┐
│ Windows + WSL2 (共享网络栈) │
│ localhost:8080 ← ✅ 直接可达 │
│ │
│ ┌───────────────────────────────────────┐ │
│ │ Docker host network │ │
│ │ granian → :8080 (直接在宿主网络) │ │
│ └───────────────────────────────────────┘ │
└─────────────────────────────────────────────┘
4. 解决方案
提供三种方案,按推荐程度排序:
方案一:修复 .wslconfig + Docker host 网络(推荐 ✅)
步骤 1 :修复 .wslconfig
编辑 C:\Users\<用户名>\.wslconfig:
ini
[wsl2]
networkingMode=mirrored
autoProxy=true
步骤 2:重启 WSL 使配置生效
在 Windows PowerShell 中:
powershell
wsl --shutdown
然后重新打开 WSL 终端。
步骤 3:重建 SearXNG 容器,使用 host 网络
bash
# 获取卷路径
CONFIG_VOL=$(docker inspect searxng --format '{{range .Mounts}}{{if eq .Destination "/etc/searxng"}}{{.Source}}{{end}}{{end}}')
CACHE_VOL=$(docker inspect searxng --format '{{range .Mounts}}{{if eq .Destination "/var/cache/searxng"}}{{.Source}}{{end}}{{end}}')
# 停止并删除旧容器
docker stop searxng && docker rm searxng
# 使用 host 网络重建
docker run -d \
--name searxng \
--restart unless-stopped \
--network host \
-v ${CONFIG_VOL}:/etc/searxng \
-v ${CACHE_VOL}:/var/cache/searxng \
ghcr.io/searxng/searxng:latest
步骤 4:验证
- Windows 浏览器访问
http://localhost:8080
优点:一劳永逸,WSL2 与 Windows 完全共享网络栈,所有服务均可通过 localhost 互访。
缺点:需要重启 WSL,会中断 WSL 中正在运行的所有进程。
方案二:netsh 端口代理(无需重启 WSL)
在 Windows PowerShell(管理员)中执行:
powershell
# 获取当前 WSL IP
$wslIp = wsl hostname -I
$wslIp = $wslIp.Trim().Split()[0]
# 设置端口代理: localhost:8888 → WSL_IP:8080
netsh interface portproxy add v4tov4 `
listenport=8888 listenaddress=127.0.0.1 `
connectport=8080 connectaddress=$wslIp
# 可选:允许局域网访问
netsh interface portproxy add v4tov4 `
listenport=8888 listenaddress=0.0.0.0 `
connectport=8080 connectaddress=$wslIp
验证:
powershell
netsh interface portproxy show all
优点:即时生效,无需重启 WSL。
缺点:
- 需要管理员权限
- WSL IP 每次重启可能变化,需重新执行
- 可被 Windows 防火墙拦截,需添加入站规则
方案三:自动端口代理脚本(方案二的自动化)
将以下脚本保存到 C:\Users\<用户名>\Desktop\setup_searxng_proxy.bat,每次 WSL 重启后以管理员身份运行:
bat
@echo off
:: SearXNG 端口代理设置脚本
:: 需要以管理员身份运行
echo === SearXNG Port Proxy Setup ===
:: 获取 WSL IP
for /f "tokens=1" %%a in ('wsl hostname -I') do set WSL_IP=%%a
echo WSL IP: %WSL_IP%
:: 清除旧代理
netsh interface portproxy delete v4tov4 listenport=8888 listenaddress=127.0.0.1 >nul 2>&1
netsh interface portproxy delete v4tov4 listenport=8888 listenaddress=0.0.0.0 >nul 2>&1
:: 设置新代理
netsh interface portproxy add v4tov4 listenport=8888 listenaddress=127.0.0.1 connectport=8080 connectaddress=%WSL_IP%
netsh interface portproxy add v4tov4 listenport=8888 listenaddress=0.0.0.0 connectport=8080 connectaddress=%WSL_IP%
echo.
echo === Current Port Proxy Rules ===
netsh interface portproxy show all
echo.
echo SearXNG: http://localhost:8888
pause
5. 排查过程记录
第一步:确认服务状态
bash
# WSL2 内部验证
curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8888
# → 200 ✅
# Docker 容器状态
docker ps --filter name=searxng
# → Up, 端口 0.0.0.0:8888->8080/tcp
第二步:确认 Windows 侧连通性
powershell
# Windows PowerShell
curl.exe http://localhost:8888
# → curl: (7) Failed to connect to localhost port 8888 ❌
# 通过 WSL IP
curl.exe http://172.18.14.110:8080
# → HTTP 200 ✅
结论:服务本身正常,问题在网络层------Windows localhost 未路由到 WSL2。
第三步:检查 WSL2 网络模式
bash
# 检查 WSL2 IP
ip addr show eth0 | grep inet
# → 172.18.14.110/20 ← NAT 模式的特征(mirrored 模式下 eth0 应与 Windows 共享 IP)
# 检查 .wslconfig
cat /mnt/c/Users/comed/.wslconfig
# → networkingMode=mirrored ← 缺少 [wsl2] header!
发现根因:.wslconfig 格式错误导致 mirrored 模式未生效。
第四步:检查 Docker 网络模式
bash
docker inspect searxng --format '{{.HostConfig.NetworkMode}}'
# → bridge
docker inspect searxng --format '{{json .HostConfig.PortBindings}}'
# → {"8080/tcp":[{"HostIp":"","HostPort":"8888"}]}
bridge 模式下 docker-proxy 在 WSL2 命名空间内监听,Windows localhost 无法直达。
第五步:确认 SearXNG 实际监听端口
bash
docker inspect searxng --format '{{range .Config.Env}}{{println .}}{{end}}' | grep PORT
# → GRANIAN_PORT=8080
容器内 granian 监听 8080,而非 settings.yml 中的 8888。
6. 关键知识点
WSL2 网络模式对比
| 特性 | NAT(默认) | Mirrored |
|---|---|---|
| WSL2 有独立 IP | ✅ (172.x.x.x) | ❌ (共享 Windows IP) |
| localhost 互通 | ❌ | ✅ |
| 外部设备访问 WSL | 需端口转发 | 直接可达 |
| .wslconfig 配置 | 不需要 | [wsl2] header 必需 |
| WSL 最低版本 | --- | 2.0+ |
Docker 网络模式对比(WSL2 环境下)
| 特性 | bridge + -p | host |
|---|---|---|
| 容器有独立 IP | ✅ | ❌ (共享宿主网络) |
| 端口映射 | 需要 -p | 不需要(直接监听宿主端口) |
| Windows localhost 可达 | ❌ (NAT 模式下) | ❌ (NAT 模式下) |
| mirrored 模式下 Windows 可达 | ✅ | ✅ |
| 端口冲突风险 | 低 | 高 |
SearXNG 端口优先级
GRANIAN_PORT 环境变量 > settings.yml 中的 port 配置 > 默认值 8080
7. 当前环境信息
| 项目 | 值 |
|---|---|
| Windows 版本 | 10.0.26200.8457 |
| WSL 版本 | 2.5.7.0 |
| WSL 内核 | 6.6.87.1-1 |
| Docker | Linux 原生 (非 Docker Desktop) |
| SearXNG 镜像 | ghcr.io/searxng/searxng:2026.5.23 |
| SearXNG Web Server | granian (GRANIAN_PORT=8080) |
| 当前 WSL IP | 172.18.14.110 |
| 当前 Docker 网络模式 | host |
| .wslconfig | 已修复 (含 [wsl2] header) |
8. 待完成操作
-
执行
wsl --shutdown重启 WSL,使 mirrored 模式生效 -
重启后验证 Windows
http://localhost:8080可访问 SearXNG -
确认 mirrored 模式生效后,可选择删除端口代理规则:
powershellnetsh interface portproxy delete v4tov4 listenport=8888 listenaddress=127.0.0.1 netsh interface portproxy delete v4tov4 listenport=8888 listenaddress=0.0.0.0
文档生成时间: 2026-05-29 22:35 (Asia/Shanghai)