问题现象
2026-10-15,经本机 mihomo 代理访问 GitHub 时 curl 报错:
curl -vS --max-time 20 -x http://127.0.0.1:7890 https://api.github.com/
* CONNECT tunnel established, response 200
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLS connect error: error:0A000126:SSL routines::unexpected eof while reading
curl: (35) TLS connect error: error:0A000126:SSL routines::unexpected eof while reading
同一时刻访问 https://www.google.com/ 也报同样的 unexpected eof。特征是 TCP 隧道已建立(CONNECT 返回 200),但 TLS 握手阶段被对端掐断。
根因分析
不是 curl 命令的问题,也不是 GitHub 相关路由规则的问题。
查 mihomo 日志,找到确证:
[TCP] dial 节点选择 (match GeoSite/github) --> github.com:443
error: sg-3-1.noraven.com:443 connect error:
dial tcp 201.4.48.114:443: connect: connection refused
即:「节点选择」当前挂在 新加坡-SG-3-1 这个节点上,而该节点拒连(connection refused),于是所有走「节点选择」的流量全部失败。curl 看到的 unexpected eof 就是节点在 TLS 握手前把连接掐掉的表现。
- 受影响面:github / google / cloudflare / microsoft / youtube / Telegram(149.154.167.x)等一切走「节点选择」的目标,全部返回 000。
- 与 GitHub 下载聚合规则无关:
api.github.com不在「下载聚合-github」的域名清单里(清单只有 codeload / objects.githubusercontent.com / release-assets / github-releases / media / raw.githubusercontent.com),它命中的是GEOSite,github → 节点选择。 - 节点池本身是好的:走其它组(下载聚合-nixos / -docker)及国内直连均正常;逐节点扫描 33 个节点对 github.com 全部 200。
直接原因 = 「自动选择」停在一个瞬时死掉的节点上、且组的健康检查没及时把它踢掉。
处置
1. 即时止血:切换出口节点
把「节点选择」从卡死的「自动选择」切到一个在线节点,立刻恢复:
curl -X PUT "http://127.0.0.1:9091/proxies/节点选择" -d '{"name":"日本-OS-2-流量倍率:0.6"}'
# 恢复后切回自动: -d '{"name":"自动选择"}'
2. 重启容器,重跑健康检查
DOCKER_HOST=unix:///run/user/1000/docker.sock docker restart clash
3. 参数硬化(让节点抖动自动切换、免人工干预)
把「坏节点能赖着不走多久」压到最短,并让检查更快判失败:
| 参数 | 原值 | 新值 | 作用 |
|---|---|---|---|
| interval(所有 url-test / load-balance 组) | 300 | 60 | 每分钟重测,坏节点最多影响 1 分钟 |
| timeout | 5000 | 2000 | 慢/死节点更快判失败被剔除 |
| tolerance(url-test) | 100 | 50 | 稍快即切,更积极 |
| provider health-check interval | 300 | 150 | 节点更快被标生死,候选池不含死节点 |
实测证据
- 切换节点前:
api.github.com连打 8 次全失败(000)。 - 切到
日本-OS-2后:api.github.com → 200。 - 逐节点扫描(临时 mihomo 实例测 github.com/robots.txt):33 个节点全部 200,耗时 0.64–2.55s;连先前拒连的
SG-3-1也恢复到 0.68s。 - 重启后组选择:
自动选择 → 新加坡-SG-3-2,谷歌 → 日本-TY-1。
诊断命令
| 用途 | 命令 |
|---|---|
| 看是不是节点拒连 | docker logs --since 90s clash | grep -iE "refused|error" |
| 看当前选中链 | curl -s http://127.0.0.1:9091/proxies(读 节点选择 / 自动选择 的 now) |
| 强制某组重测(URL 用该组自己的检查地址) | curl "http://127.0.0.1:9091/group/自动选择/delay?url=https%3A%2F%2Fcache.nixos.org%2Fnix-cache-info&timeout=3000" |
| 切换出口节点 | curl -X PUT "http://127.0.0.1:9091/proxies/节点选择" -d '{"name":"自动选择"}' |
踩坑记录
- 现象:curl 报
error:0A000126:SSL routines::unexpected eof while reading。成因:出口节点拒连,TLS 握手被掐断。处置:查日志确认 refused,切节点。 - 现象:
PUT /configs热重载后健康检查疑似停摆(组选中的节点长期不改)。成因:热重载未重跑全部健康检查。处置:改用docker restart clash,让其从头做一轮检查。 - 现象:一个组只配一个健康检查 URL。成因:用
cache.nixos.org检查的组会挑出"连 nix 快、连 google/telegram 慢"的节点,自以为健康因而不会切换。处置:按目标拆组、每组用自己目标的 URL 做检查。
边界
- 本档只记录本机 mihomo(Docker)代理的 curl / GitHub 访问故障定位与处置,不含节点订阅本身的采购与更换。
- url-test 只按 RTT 排序,测不出"活着但很慢 / 丢包"的节点;整个订阅池大面积挂掉时,任何参数都无法自愈。
- 「下载聚合」及「谷歌」组的路由规则不在本故障的成因内,勿混为一谈。