04. 用 mihomo (Clash.Meta) 解决出口问题
境内 VPS 直连 OpenAI / Google / Anthropic 通常失败,且 ChatGPT 不接受香港、中国大陆出口,必须走美/日/新等支持地区。这一步在服务器上跑一个 mihomo 容器,CPA 通过它出网。
为什么是 mihomo
- 原版 Clash 仓库已删,
mihomo(前 Clash.Meta) 是最活跃的开源继任。 - 协议覆盖广(Vmess/Vless/Trojan/Shadowsocks/Hysteria/Reality 等)。
- 自带 RESTful 控制接口 + Web 面板,命令行/浏览器都能切节点。
- 官方多架构镜像
metacubex/mihomo,开箱即用。
1) 拿到订阅链接
机场卖家会给一个订阅 URL,比如:
https://www.example.com/link/xxxxxxxx?clash=1
带 clash=1 或者 User-Agent 带 clash 时,服务端会直接返回 clash 格式的 yaml 配置,省掉转换步骤。
2) 下载配置
mkdir -p /root/mihomo && cd /root/mihomo
curl -L -A "clash.meta" "你的订阅URL" -o config.yaml
head -20 config.yaml期望开头能看到类似:
port: 7890
socks-port: 7891
allow-lan: false
mode: Rule
external-controller: '0.0.0.0:9090'
dns:
enable: true
listen: '0.0.0.0:53'
...3) 调整两处必改项
a. allow-lan: false → true
Docker 容器之间互访需要这个,否则 CPA 容器连不上 mihomo。
sed -i 's/^allow-lan: false/allow-lan: true/' /root/mihomo/config.yamlb. DNS 端口 53 → 1053
0.0.0.0:53 在 host 网络模式下会和 systemd-resolved 抢端口,启动会失败。换成非常用端口就行。
sed -i "s|listen: '0.0.0.0:53'|listen: '0.0.0.0:1053'|" /root/mihomo/config.yamlmihomo 的 DNS 监听只是把自己当成一个 DNS server,给本地用。CPA 走 HTTP 代理协议,根本不会用到这个 DNS 监听端口,所以改不改都不影响 CPA。但保留默认 53 会让 mihomo 容器起不来。
验证修改
grep -E "^(port|socks-port|allow-lan|external-controller)" /root/mihomo/config.yaml
grep "listen:" /root/mihomo/config.yaml4) 起容器
最简单方式:host 网络。
docker run -d \
--name mihomo \
--restart unless-stopped \
--network host \
-v /root/mihomo/config.yaml:/root/.config/mihomo/config.yaml \
metacubex/mihomo:latest
docker logs --tail 20 mihomo期望日志:
Start initial configuration in progress
Geodata Loader mode: memconservative
Geosite Matcher implementation: succinct
Initial configuration complete, total time: Xms
5) 验证代理能通
curl -x http://127.0.0.1:7890 -I --max-time 10 https://www.google.com
curl -x http://127.0.0.1:7890 --max-time 10 -s https://api.openai.com/cdn-cgi/trace第二条返回里应有 loc=US,说明出口在美国。如果 loc=HK,ChatGPT 一定登录失败,立刻切节点(下一节)。
6) 通过 RESTful API 切节点
mihomo 的 external-controller 默认监听 :9090。所有切节点操作都是 PUT 到 /proxies/<组名>。
列出所有 selector 组
curl -s http://127.0.0.1:9090/proxies | python3 -c "import json,sys;d=json.load(sys.stdin)['proxies'];[print(n,'->',p.get('now'),'(',len(p.get('all',[])),'options)') for n,p in d.items() if p['type']=='Selector']"输出大概像:
🔰Proxy -> HK IEPL专线 11 | 倍率 3x ( 25 options)
🌍国外媒体 -> 🔰Proxy ( 26 options)
📺Netflix -> 🔰Proxy ( 26 options)
...
看某个组里的所有节点
curl -s "http://127.0.0.1:9090/proxies/🔰Proxy" | python3 -c "import json,sys;d=json.load(sys.stdin);[print(i,n) for i,n in enumerate(d['all'])]"切节点
curl -X PUT http://127.0.0.1:9090/proxies/🔰Proxy \
-H "Content-Type: application/json" \
-d '{"name":"US Pro 11 | 倍率 2x"}'成功无输出(HTTP 204)。验证:
curl -s http://127.0.0.1:9090/proxies/🔰Proxy | python3 -c "import json,sys;print('now:',json.load(sys.stdin)['now'])"有些机场把 OpenAI 的流量单独路由到
🌍国外媒体或🤖OpenAI之类的组——如果切了主组还是走错节点,列出所有 selector 看一下,对应组也切到美国节点。
实战:判断应该切哪个组
先列出所有可切换组:
curl -s http://127.0.0.1:9090/proxies | python3 -c "import json,sys;d=json.load(sys.stdin)['proxies'];[print(k, '->', v.get('type'), '->', v.get('now')) for k,v in d.items() if v.get('type') in ['Selector','URLTest','Fallback']]"本次服务器输出类似:
GLOBAL -> Selector -> DIRECT
⚓️其他流量 -> Selector -> 🔰Proxy
🌍国外媒体 -> Selector -> 🔰Proxy
🍎苹果服务 -> Selector -> 🚀直接连接
📟Twitter -> Selector -> 🔰Proxy
📲Telegram -> Selector -> 🔰Proxy
📺Netflix -> Selector -> 🔰Proxy
📺Youtube -> Selector -> 🔰Proxy
🔰Proxy -> Selector -> US Pro 11 | 倍率 2x
🚀直接连接 -> Selector -> DIRECT这里真正要切的是:
🔰Proxy因为其它国外流量组都指向 🔰Proxy。只要切 🔰Proxy,OpenAI、Telegram、Twitter、YouTube 等通常都会跟着走新节点。
查看 🔰Proxy 里的节点:
curl -s "http://127.0.0.1:9090/proxies/🔰Proxy" | python3 -c "import json,sys;d=json.load(sys.stdin);print('\n'.join(d.get('all',[])))"切到某个节点:
curl -X PUT "http://127.0.0.1:9090/proxies/🔰Proxy" \
-H "Content-Type: application/json" \
-d '{"name":"US Pro 12 | 倍率 2x"}'确认当前节点:
curl -s http://127.0.0.1:9090/proxies | python3 -c "import json,sys;d=json.load(sys.stdin)['proxies'];print(d['🔰Proxy']['now'])"7) 批量测试节点是否适合 OpenAI
只看到:
HTTP/1.1 200 Connection established不代表 OpenAI 通了。它只说明本机成功连上 mihomo,并且 mihomo 开始建立代理隧道。
如果后面出现:
curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL说明 TLS 握手失败,节点到 OpenAI 这一段不稳定或被阻断。
测试命令:
curl -x http://127.0.0.1:7890 -I https://api.openai.com --max-time 15可用节点常见返回:
HTTP/1.1 200 Connection established
HTTP/2 421HTTP/2 421 对这个 HEAD / 请求来说可以视为连通,说明 TLS 已经通了。403、404、421、200 都比 SSL_ERROR_SYSCALL 好,至少代表能完成 HTTPS 握手。
本次批量测试脚本:
for n in \
"US Pro 12 | 倍率 2x" \
"US Pro 13 | 倍率 2x" \
"US Pro 14 | 倍率 2x" \
"US Pro 11 | 倍率 2x" \
"SG IEPL专线 51 | 倍率 3x" \
"JP Pro 01 | 倍率 2x"
do
echo "===== $n ====="
curl -s -X PUT "http://127.0.0.1:9090/proxies/🔰Proxy" \
-H "Content-Type: application/json" \
-d "{\"name\":\"$n\"}"
sleep 2
curl -x http://127.0.0.1:7890 -I https://api.openai.com --max-time 12 2>&1 | head -8
done本次结果:
| 节点 | OpenAI 测试结果 | 结论 |
|---|---|---|
| `US Pro 12 | 倍率 2x` | HTTP/2 421 |
| `US Pro 13 | 倍率 2x` | HTTP/2 421 |
| `JP Pro 01 | 倍率 2x` | HTTP/2 421 |
| `US Pro 14 | 倍率 2x` | SSL_ERROR_SYSCALL |
| `US Pro 11 | 倍率 2x` | SSL_ERROR_SYSCALL |
| `SG IEPL专线 51 | 倍率 3x` | SSL_ERROR_SYSCALL |
最终切到:
curl -X PUT "http://127.0.0.1:9090/proxies/🔰Proxy" \
-H "Content-Type: application/json" \
-d '{"name":"US Pro 12 | 倍率 2x"}'验证:
curl -x http://127.0.0.1:7890 -I https://api.openai.com --max-time 15
curl -x http://127.0.0.1:7890 -I https://registry-1.docker.io/v2/ --max-time 15判断标准:
| 测试目标 | 可用表现 |
|---|---|
| OpenAI | 第二段出现 HTTP/2 421、403、404、200 等 |
| Docker Hub | HTTP/2 401,这是未认证 Registry 的正常响应 |
如果 CPA / Codex / Docker 拉镜像后续又不稳定,优先在这些节点之间切:
US Pro 12 | 倍率 2x
US Pro 13 | 倍率 2x
JP Pro 01 | 倍率 2x8) Web 面板(可选)
浏览器打开 metacubexd,host 填服务器 IP,port 填 9090,secret 留空。可视化切节点、看流量、测延迟。
⚠️ 9090 端口默认无 secret,必须用安全组或 iptables 限制只允许你自己的 IP,否则任何人都能控制你的代理。也可以通过 SSH 隧道访问:
ssh -L 9090:127.0.0.1:9090 root@服务器IP # 然后浏览器开 http://127.0.0.1:9090(注意 metacubexd 要填这个本地地址)
9) ChatGPT/OpenAI 友好节点的判断
不是所有美国节点都能登录 ChatGPT,常见拒登原因:
- 节点 IP 在 datacenter 段(机场普遍)→ 大概率会被风控
- IP 被滥用(共享池)→ 会要求过 captcha 甚至直接拒登
- 出口实际是英国/法国虽然 IP 显示美国
实战建议:
- 优先选纯净美国住宅 / 商业 IP节点,机场页面通常会标注。
- 同一节点登录失败就换一条,不要在同一节点反复试。
- 验证节点对 ChatGPT 友好:
curl -x http://127.0.0.1:7890 https://chat.openai.com/cdn-cgi/trace看loc=US且colo是美国机房代码(如IADSJCLAX)。
10) 让 CPA 走这个代理
回到 03-deploy-cpa.md §5 改 proxy-url。
下一步:05-oauth-login.md 完成 OAuth 登录。