Linux 下排查与修复 Mihomo 网络代理环境

问题背景

Linux 服务器上,mihomo 服务已经启动,但访问部分外网服务时出现超时,日志中有类似报错:

1
[TCP] dial PROXY ... --> chat.openai.com:443 error: connect failed: ... i/o timeout

同时也出现过对元数据地址的超时:

1
169.254.169.254:80 error: connect failed: ... i/o timeout

解决办法

第一步:确认 Mihomo 服务本身是否正常

  • 先检查服务状态:
    1
    systemctl status mihomo -l --no-pager
  • 结论:
    • mihomo 服务状态为 active (running)
    • 说明服务本身没有挂掉;
    • 问题更可能出在 规则配置代理节点 选择;

第二步:定位第一类问题

元数据地址 169.254.169.254 被错误走代理

日志里出现:

1
[TCP] dial PROXY ... --> 169.254.169.254:80 error: connect failed: ... i/o timeout

这说明:

  • 本机程序访问了 169.254.169.254
  • Mihomo 把它命中了最后的 MATCH,PROXY
  • 该地址被送去代理
  • 最终超时

原因
169.254.169.254 是典型的:

  • 云主机元数据地址
  • 链路本地地址
  • 不应该走代理

第三步:修复第一类问题:给内网/元数据地址加直连规则

原始配置文件:
/etc/mihomo/config.yaml

原规则片段:

1
2
3
4
5
6
7
rules:
- DOMAIN-SUFFIX,localhost,DIRECT
- IP-CIDR,127.0.0.0/8,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,192.168.0.0/16,DIRECT,no-resolve
- MATCH,PROXY

应改为:

1
2
3
4
5
6
7
8
9
10
11
rules:
- DOMAIN-SUFFIX,localhost,DIRECT
- IP-CIDR,127.0.0.0/8,DIRECT,no-resolve
- IP-CIDR,169.254.169.254/32,DIRECT,no-resolve
- IP-CIDR,169.254.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,192.168.0.0/16,DIRECT,no-resolve
- IP-CIDR,100.64.0.0/10,DIRECT,no-resolve
- IP-CIDR,100.100.100.200/32,DIRECT,no-resolve
- MATCH,PROXY

说明

  • 169.254.169.254/32:云元数据地址直连
  • 169.254.0.0/16:整段链路本地地址直连
  • 100.64.0.0/10CGNAT 段直连
  • 100.100.100.200/32:云环境常见内部服务地址直连

第四步:重启 Mihomo 并验证规则是否生效

  • 重启服务:systemctl restart mihomo

  • 查看最近日志:journalctl -u mihomo -n 30 --no-pager

  • 修复后的日志中出现:

    1
    198.18.0.1:46740 --> 100.100.100.10:80 match IPCIDR(100.64.0.0/10) using DIRECT

这说明:

  • 新加的内网直连规则已经生效
  • 第一类问题已经解决

第五步:定位第二类问题

OpenAI / Google 超时并不是 Mihomo 挂了,而是 PROXY 组当前选中了 DIRECT

虽然日志里显示:

1
dial PROXY ... --> chat.openai.com:443 error: ... timeout

但这并不一定表示真的走了代理节点

需要检查 PROXY 分组当前选中的到底是谁:

1
curl -s http://127.0.0.1:9090/proxies/PROXY
  • 返回结果中的关键字段:"now":"DIRECT"
  • 结论:
    • PROXY 组当前实际选中的是 DIRECT
    • 所以:一下这些流量虽然 “名义上走 PROXY 组”,实际上却是 直连,而在当前服务器环境里,直连这些域名会超时
      • chat.openai.com
      • chatgpt.com
      • ab.chatgpt.com
      • mtalk.google.com

第六步:把 PROXY 手动切换到真实代理节点

  • 切到一个美国节点:

    1
    2
    3
    curl -X PUT http://127.0.0.1:9090/proxies/PROXY \
    -H 'Content-Type: application/json' \
    -d '{"name":"🇺🇸美国圣何塞01 | 三网推荐"}'
  • 切到一个日本节点:

    1
    2
    3
    curl -X PUT http://127.0.0.1:9090/proxies/PROXY \
    -H 'Content-Type: application/json' \
    -d '{"name":"🇯🇵日本东京06-0.1倍 | 高速专线推荐"}'
  • 切换后再次确认:

    curl -s http://127.0.0.1:9090/proxies/PROXY

  • 确认返回里的:"now":"某个真实节点名"

第七步:测试代理是否恢复正常

以下命令测试:

1
curl -x http://127.0.0.1:7890 -I https://chat.openai.com --max-time 20

如果返回正常的 HTTP 响应头,说明代理链路已经恢复。

第八步:当前配置的潜在问题

当前 proxy-groups 配置为:

1
2
3
4
5
6
7
proxy-groups:
- name: PROXY
type: select
use:
- mysub
proxies:
- DIRECT

这会导致一个常见问题:

PROXY 组很容易被手动或默认选成 DIRECT;一旦如此,OpenAI/Google 等流量就会直连失败。

更推荐的改法

建议把 PROXY 改成自动测速选择,而不是保留 DIRECT 在组里:

1
2
3
4
5
6
7
proxy-groups:
- name: PROXY
type: url-test
use:
- mysub
url: http://www.gstatic.com/generate_204
interval: 300

好处

  • 自动选择可用节点
  • 避免 PROXY 长时间停留在 DIRECT
  • 更适合服务器长期运行

建议

  • DIRECT 不要放进 PROXY 候选组
  • 直连应该通过 rules 显式控制,而不是靠代理组兜底