局域网代理 502 问题排查文档
日期:2026-08-14 环境:a1(Debian 13)+ hi-box(192.168.31.82,mihomo + cpa) 涉及组件:pi(coding-agent)、opencode、mihomo(7890)、cli-proxy-api / cpa(8317)
问题现象
opencode 通过 cpa(http://192.168.31.82:8317)连接时报:
AI_APICallError: Bad Gateway
Bad Gateway [retrying in 2s attempt #2]排查经过
第一层排查:cpa 本身是否正常
ssh hi-box "curl http://127.0.0.1:8317/v1/models"→ HTTP 200,cpa 自身正常- cpa 配置中
deepseek-v4-flash映射了 4 个上游,round-robin 轮询sensenova/api.pie-xian.com/opencode.ai/yjjhwjw.com
yjjhwjw.com完全不可达,cparequest-retry: 2+max-retry-interval: 30, 每次轮询到它卡 30 秒 × 3 次 = 90 秒 → 超时 → opencode 报 502
阶段方案:禁用 yjjhwjw(已解决)
第二层排查:opencode 配置字段名错误
- opencode 配置文件写的是
"provider"(单数),但实际读的是"providers"(复数) - 导致
opencode debug config输出 providers 为空{} - 但 opencode 运行时仍然尝试用 cpa,因为运行时可能从其他路径加载
修正:改为 "provider"(查了 JSON Schema 后确认 opencode 1.18.16 用的是单数 provider)
第三层排查:Node.js 不支持 CIDR 格式的 NO_PROXY
这是根本原因。
~/.bashrc和~/.profile中设置了NO_PROXY="192.168.0.0/16"- curl 8.14 支持 CIDR → curl 能绕过代理直连 → HTTP 200
- Node.js/undici 不支持 CIDR → Node.js 认为 192.168.31.82 不在 NO_PROXY 中 → 流量被发到代理 7890
- 但代理 7890 此时已挂 → 连接失败 → HTTP 000 / 502
这就是为什么 curl 通了但 opencode(Node.js 应用)不通。
阶段方案:把 NO_PROXY 改成精确 IP 192.168.31.82
第四层排查:systemd 用户会话固化了旧环境变量
- 改了
.bashrc/.profile后仍然不通,因为 systemd user manager 在登录时就固化了环境变量 systemctl --user show-environment仍显示旧的NO_PROXY=192.168.0.0/16- 所有新进程(包括 pi agent、opencode)都继承这个固化环境
修正:
bash
systemctl --user set-environment NO_PROXY="..."第五层排查:gsettings 代理模式
gsettings get org.gnome.system.proxy mode返回'manual'- 某些图形应用可能从这里读取代理配置
- 虽然 opencode 是 TUI 不读这个,但保持环境一致是必要的
最终一劳永逸方案
核心思路:让 mihomo 代理自己负责路由判断,客户端不用管 NO_PROXY。
在 hi-box 的 mihomo 配置中,在 rules 最前面加局域网直连规则:
yaml
rules:
- 'IP-CIDR,192.168.0.0/16,DIRECT,no-resolve'
- 'IP-CIDR,10.0.0.0/8,DIRECT,no-resolve'
- 'IP-CIDR,172.16.0.0/12,DIRECT,no-resolve'
- 'IP-CIDR,127.0.0.0/8,DIRECT,no-resolve'
- 'GEOIP,CN,DIRECT'
- ...
- 'MATCH,ALL'这样:
- 客户端(pi/opencode)所有流量都发代理 7890
- mihomo 收到请求后检查目标 IP
- 是局域网 → DIRECT 直连(不走 VPN,不绕圈)
- 是外网 → 走代理
好处:
- 客户端 NO_PROXY 只写
localhost,127.0.0.1即可 - 不再受 Node.js 不支持 CIDR 的限制
- 即使代理重启了,局域网流量仍然能被代理正确路由
最终文件清单
| 文件 | 关键内容 |
|---|---|
/etc/mihomo/config.yaml(hi-box) | rules 顶部加了 4 条 IP-CIDR 直连规则 |
~/.bashrc | NO_PROXY="localhost,127.0.0.1,192.168.*,10.*,172.16.*,*.cn" |
~/.profile | 同上 |
/mnt/shared/.opencode/opencode.json | provider.cpa + provider.sensenova-* |
/mnt/shared/.pi/agent/models.json | cpa-001 provider + sensenova provider |
/mnt/shared/CPA/config.yaml(hi-box) | yjjhwjw 已 disabled: true |
环境变量(systemd user)
http_proxy=http://192.168.31.82:7890
https_proxy=http://192.168.31.82:7890
ALL_PROXY=http://192.168.31.82:7890
NO_PROXY=localhost,127.0.0.1故障快速恢复命令
bash
# hi-box 重启 mihomo
ssh hi-box "systemctl restart mihomo"
# hi-box 重启 cpa
ssh hi-box "kill \$(pgrep cli-proxy-api); sleep 1; /usr/local/bin/cli-proxy-api -config /mnt/shared/CPA/config.yaml &"
# a1 更新 systemd 环境
systemctl --user set-environment http_proxy=http://192.168.31.82:7890 https_proxy=http://192.168.31.82:7890 ALL_PROXY=http://192.168.31.82:7890 NO_PROXY=localhost,127.0.0.1
# a1 清当前 shell
unset http_proxy https_proxy ALL_PROXY all_proxy NO_PROXY no_proxy经验教训
- curl 通 ≠ Node.js 通。Node.js 的 proxy/undici 实现与 curl 对
NO_PROXY的解析规则不同(不支持 CIDR) - systemd 用户会话固化环境变量。改
.bashrc不够,必须用systemctl --user set-environment - 代理挂了的表象是 502,不是 connection refused,容易误判为上游问题
- 一劳永逸 = 让代理层做路由决策,不要让客户端猜