Zjuconnect_Docker_WSL2
🐛 Debug 记录:zju-connect (aTrust) WSL2+Docker Desktop 验证码访问死锁与持久化部署
1. 环境信息
- 软件版本:mythologyli/zju-connect:latest
- 协议:aTrust
- 运行环境:Windows 宿主机 + WSL2(Ubuntu 发行版) + Docker Desktop
- 部署方式:Docker Compose
2. 初始目标
参考配置部署 zju-connect 客户端,对接 aTrust 协议 VPN,实现容器内登录凭据持久化,完成一次性交互式登录后,可长期后台无感运行代理服务。
3. 问题排查过程
❌ 踩坑 1:本地镜像版本非最新,存在兼容性风险
- 现象:执行
docker run启动容器后,通过docker images发现本地镜像为 2 个月前的旧版本,与 Docker Hub 远程 latest 标签的镜像摘要不一致。 - 原因:Docker 不会自动拉取
latest标签的最新镜像,仅会使用本地已存在的同名镜像,导致本地版本落后。 - 修复:手动执行
docker pull mythologyli/zju-connect:latest强制拉取远程最新镜像,并对比本地与远程镜像摘要确认版本一致。
❌ 踩坑 2:无头环境下验证码服务无法访问
- 现象:执行
docker compose run --rm -it zju-connect触发交互式登录,日志报错Failed to open browser: exec: "xdg-open": executable file not found in $PATH. Please visit: http://127.0.0.1:36833;WSL2 内执行curl http://127.0.0.1:36833报错Connection refused,Windows 宿主机浏览器也无法打开该地址。 - 原因:
- 容器内无图形界面工具
xdg-open,无法自动弹出浏览器。 - 查阅源码发现,zju-connect 验证码服务启动时强制执行
net.Listen("tcp", "127.0.0.1:0"),强制绑定容器本地回环地址(仅容器内部可访问),且端口随机分配,常规-p端口映射仅能转发监听在0.0.0.0的端口,对该地址完全无效。
- 容器内无图形界面工具
❌ 踩坑 3:network_mode: host 配置不生效
- 现象:在
docker-compose.yml中添加network_mode: "host"后重新启动容器,WSL2 内执行ss -tuln | grep 36833无任何输出,端口未监听;通过docker inspect查看容器实际网络模式,发现为bridge而非配置的host。 - 原因:
- Docker 官方设计行为:
docker compose run启动的临时容器,不会继承 service 中定义的 network_mode 网络配置,必须通过--network=host参数显式指定。 - Docker Desktop 网络隔离限制:Windows/WSL2 环境下,
network_mode: host绑定的是 Docker 背后隐藏的 Linux 虚拟机的本地回环地址,而非 WSL2 虚拟机/Windows 宿主机的回环地址,导致端口无法跨网络访问。
- Docker 官方设计行为:
❌ 踩坑 4:常规端口映射方案完全失效
- 现象:尝试通过
-p提前映射端口,但由于验证码端口随机分配,无法在docker-compose.yml中写死规则;即使临时映射,也因服务绑定127.0.0.1而无法访问。 - 原因:验证码服务强制绑定
127.0.0.1且端口随机,常规端口映射无法突破容器本地回环限制。
4. 最终破局方案
核心思路:“一次性原生方式完成交互式登录,生成持久化凭据后,交由 Docker 长期稳定后台运行”,既规避 Docker 网络隔离的核心卡点,又保证长期运行的稳定性。
具体步骤:
- 更新镜像至最新版本
- 停止并清理旧容器:
docker stop zju-connect && docker rm zju-connect - 强制拉取远程最新镜像:
docker pull mythologyli/zju-connect:latest - 验证版本一致性:对比本地与远程镜像摘要,确认已更新至最新版。
- 停止并清理旧容器:
- 配置 Docker Compose 持久化环境 编写
docker-compose.yml,核心配置本地目录挂载,保证登录凭据可持久化、跨容器复用:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
version: '3.8' services: zju-connect: container_name: zju-connect image: mythologyli/zju-connect restart: unless-stopped ports: - "1080:1080" # socks5 代理端口 - "1081:1081" # 管理端口 configs: - source: zju-connect-config target: /home/nonroot/config.toml volumes: # 核心:本地目录挂载,Windows/WSL2 均可直接访问,凭据持久化 - ./data:/home/nonroot/data configs: zju-connect-config: content: | username = "" password = "" client_data_file = "/home/nonroot/data/client_data.json" protocol = "atrust" # 验证码图片本地保存路径,兜底方案使用 graph_code_file = "/home/nonroot/data/graph_code.jpg"
- 一次性交互式登录(2种可选方案,均适配WSL2环境)
方案A:nsenter 网络转发(零侵入首选,无需改配置)
- 提前创建本地数据目录:
mkdir -p ./data - 启动交互容器,显式指定host网络,保持终端全程打开,直到日志输出验证码地址:
1
docker compose run --rm -it --network=host zju-connect
- 新开 WSL2 终端,执行一键转发命令,将容器内 127.0.0.1 的随机验证码端口转发到 WSL2 固定端口:
1 2 3 4 5 6 7 8 9 10
# 自动获取容器PID与验证码端口 CONTAINER_PID=$(docker inspect -f '' $(docker ps -q --filter "name=zju-connect")) CAPTCHA_PORT=$(docker logs $(docker ps -q --filter "name=zju-connect") | grep -oP '127.0.0.1:\K\d+' | tail -1) echo "✅ 验证码端口: $CAPTCHA_PORT" # 安装转发工具(仅首次执行) sudo apt update && sudo apt install -y socat # 启动端口转发 sudo nsenter -t $CONTAINER_PID -n socat TCP-LISTEN:18080,fork,reuseaddr TCP:127.0.0.1:$CAPTCHA_PORT
- Windows 宿主机浏览器访问
http://<WSL2_IP>:18080(WSL2_IP 可通过ip addr show eth0获取),完成图形验证码验证。 - 回到交互容器终端,输入短信验证码,看到
Client data saved to /home/nonroot/data/client_data.json提示后,按Ctrl+C退出容器与转发进程。
方案B:本地图片坐标验证(兜底方案,完全规避网络问题)
- 提前创建本地数据目录:
mkdir -p ./data - 直接启动交互容器:
docker compose run --rm -it zju-connect - 终端提示输入验证码时,打开 Windows 资源管理器,访问路径
\\wsl$\<你的WSL发行版名>\home\<用户名>\zjuvpn\data,找到graph_code.jpg验证码图片。 - 用 Windows 经典画图工具打开图片,按
Ctrl+1一键切换到 100% 缩放比例,按图片提示顺序获取文字中心的像素坐标。 - 在终端按格式输入坐标 JSON(无空格),例如
[[181,66],[250,80]],回车后按提示输入短信验证码,完成登录。
- 提前创建本地数据目录:
- Docker 长期后台运行
- 确认
./data目录下已生成client_data.json登录凭据文件。 - 后台启动容器,无需再配置 host 网络,直接使用端口映射:
1
docker compose up -d - 验证服务状态:
- 查看容器运行状态:
docker ps - 查看服务日志:
docker logs zju-connect,确认VPN client started无报错 - 代理连通性测试:
curl -x socks5://127.0.0.1:1080 https://example.com
- 查看容器运行状态:
- 确认
This post is licensed under CC BY 4.0 by the author.