| name | clash-verge-config |
| description | 以「配置即代码」管理、调试 Clash Verge Rev(mihomo 内核)客户端配置。涵盖:哪些字段扩展脚本能改 / 不能改(external-controller、secret、各端口、log-level 被内核接管)、改了为什么不生效、enhance 管线与字段归属、纯命令行让配置重新生成并生效、mihomo external controller RESTful API、external-ui 自托管面板、判断流量走没走代理 / 命中哪条规则、DNS 泄漏排查、profiles.yaml 里 profile 显示名与到期信息从哪来、节点突然全超时时先排除 IP 被墙与 TUN 回环、远程机器复用本地代理。用户在改 Clash Verge / mihomo 扩展脚本(script) / 扩展配置(merge) / 订阅规则、external-controller / secret / 端口,或抱怨「配置改了不生效」「规则不命中」「远程连不上面板」「DNS 泄漏」「profile 显示名 / 到期不对」「节点突然连不上 / 延迟测试超时」「想自动化更新代理配置」时用这个 skill。机场 / 订阅服务端搭建见 airport-deploy skill。 |
这个 Skill 解决什么
Clash Verge Rev 是个 Tauri GUI,底层跑 mihomo 内核。它的配置系统有几个反直觉但有据可查的行为,不了解会浪费大量时间瞎试。这个 skill 把这些行为的「方向」沉淀下来,让你改配置、做自动化、排查路由时直接走对路,而不是凭印象猜。
核心原则贯穿全篇:遇到不确定的工具行为,去查一手来源(官方文档 + 源码),不靠猜。 每条结论都可以、也应该在当前版本上复核。服务端(机场 / 订阅渲染)侧的问题见 [[airport-deploy]]。
心智模型一:字段归属(最重要)
运行时配置由内部函数 enhance() 生成,顺序大致是:
订阅 profile → 扩展配置(Merge) → 扩展脚本(Script) → ★ Verge 接管保留字段 ★ → 内置脚本 → tun/dns
最后那步会无条件覆盖一批保留字段——external-controller、secret、各 *-port、log-level 等。官方原话:这些字段「由程序自身控制以保证正常功能,无法被成功覆盖」。
这意味着:保留字段,扩展脚本/扩展配置改不动,写进去也会被抹掉,不是 bug。要改它们,写进 Clash Verge 自己的 clash 配置文件(应用数据目录里那个带 # 头注释的)。而 proxies、proxy-groups、rules、大多数 dns/tun/sniffer 才适合由扩展脚本控制。改了没生效时,先判断是改错层、没触发重新生成,还是规则已生效但被更早规则盖过。
内部细节、保留字段清单、配置文件角色与位置、external controller / external-ui 见 references/internals.md。
心智模型二:profiles.yaml 与「显示名 / 到期」从哪来
应用数据目录里的 profiles.yaml 是 Clash Verge 存 profile 元数据的地方:每个远程订阅的 name(面板显示名)和 extra(upload/download/total/expire 流量与到期)。
关键点:这些值是导入/更新订阅时从服务端响应头解析出来后缓存下来的——name 来自 Content-Disposition / Profile-Title,extra 来自 Subscription-Userinfo,都不是从 URL 推断的。
由此推出两个实操结论:
- 服务端改了响应头,旧 profile 不会自动变。显示名或到期不对时,要让客户端重新拉取一次(强制 auto-update 到期 / 重新导入 / 删除重加),缓存才刷新。
- Clash Verge 不热重载
profiles.yaml。要手改(配置即代码)就先退出 app,再改文件,再重启——退出在前是为了避免退出时把内存里的旧值刷回、覆盖你的修改。改完用「app 重启后实际加载的值」验证,而不是只看你写进文件的值。
心智模型三:配置即代码
推荐把全局扩展脚本当成个人规则和自建节点的叠加层:订阅提供机场节点,全局脚本幂等注入自建节点、策略组、前置规则和 DNS。换订阅时不重配个人规则,重新生成运行时配置即可。能纯命令行触发重新生成、用 external controller 读写运行时状态,就不依赖 GUI。
DNS 泄漏与分流规则
「DNS 泄漏」通常不是服务端 Reality 参数问题,而是客户端最终运行时配置没接管 DNS,或 DNS 请求走了 DIRECT/系统解析。处理方向:
- 确认最终运行时配置里确实有
dns.enable: true,且没被 Clash Verge 的 DNS 设置或全局脚本覆盖。
- 用 fake-ip / redir-host 时都要明确
nameserver、fallback/nameserver-policy 的出口意图;海外 DoH 用 https://1.1.1.1/dns-query#PROXY 这类写法强制经代理解析。
- 代理服务器自身的域名必须有直连解析通道:在 Mihomo 订阅里给
dns.proxy-server-nameserver 配国内或系统可达 DNS。普通 dns.nameserver 才放带 #PROXY 的海外 DoH。否则节点 server 也是域名时,海外 DoH 可能递归成「解析代理服务器需要先连代理」;反过来,如果普通 nameserver 直连国内 DoH,DNS leak 检测会显示国内解析器出口。
- 国内域名走国内 DoH 或直连 DNS,国外域名和 AI 服务域名经代理解析,避免本地运营商 DNS 暴露访问意图。
- 验证别只看检测网页结论,要读 mihomo
GET /connections、日志和最终配置,确认 DNS 连接命中哪条规则、走哪个出站。
跨客户端订阅不要照搬 DNS 片段。Stash 等客户端的 DNS 请求默认可能直连上游,不按普通代理规则走;mihomo 里可用的 #PROXY、海外 DoH、nameserver-policy 组合在手机端可能变成「基础 DNS 全超时」,进而让 DIRECT 和节点测速一起失败。遇到 Stash 更新订阅后所有节点超时,优先看订阅是否把桌面 Mihomo 的 #PROXY/#LEGAL DNS 原样下发给了 iOS;Stash 常见兜底是独立模板:redir-host、直连基础 DNS、入口域名 hosts、GEOIP 规则加 no-resolve。服务端应按客户端分模板,而不是改 Xray 入站参数。
Stash 的远程 API 更接近运行时控制器,不是 profile 管理器。PATCH /configs 只能改 mode、log-level、端口等少量运行项,不能用 payload 替换整份 YAML;/profiles 这类 profile 更新接口也不一定存在。验证订阅模板修复时,必须让用户在 Stash 内执行订阅更新或重新导入,再用 /proxies、/rules、/connections 读实际运行态,别把 API 返回 204 误判为整份订阅已热加载。
规则同理:从上到下首命中。排查某站没走代理时,找第一条能匹配它的规则,而不是只看最终 IP。
地理严格的站报「not supported in your country」:先验出口 IP 的 Google 地理,别先怀疑客户端
Gemini 等服务按 Google 自己的 IP 地理库判国家——它和 ip-api/ipinfo 经常不一致。VPS IP(Bandwagon 等机房段尤甚)常被 Google 标成中国,哪怕物理在美国。所以 not supported 时第一步是验出口 IP 在 Google 眼里是哪国,不是去查客户端泄露(那是罕见的次因,且 ip-api 显示干净并不能排除——要看 Google 的库)。
检测法(从该出口或经该节点 curl,不是 ip-api):
r=$(curl -s -A "Mozilla/5.0" https://gemini.google.com/)
echo "$r" | grep -q '45631641,null,true' && echo 可用 || echo 不可用
echo "$r" | grep -oE ',2,1,200,"[A-Z]{2,3}"'
USA 且"可用" = 此出口能用;CHN/"不可用" = IP 被 Google 标错国,改任何客户端/Clash/Xray 配置都救不了——只能换 IP、换节点、或给 Google 报地理纠错。买新节点先跑这条验。
只有当出口 IP 的 Google 地理确实是支持国、却仍 not supported 时,才轮到查客户端泄露:浏览器走 IPv6 直连绕过代理(运行时/订阅顶层 ipv6: false + 浏览器关 DoH);或 WebRTC 读网卡 240e: 中国 IPv6(设备/路由器关 IPv6,或——若 IPv6 要留给 Tailscale——浏览器层面限制 WebRTC)。验证用 browserleaks.com/ip 与 /webrtc。
节点突然全超时:先排除 IP 被墙,再排除 TUN 回环
某个一直能用的节点突然延迟测试全 timeout,先别怀疑订阅格式或节点参数。两个客户端侧的优先排查:
- IP 被墙:从本机网络直接对节点落地
<server-ip>:<port> 做 TCP 连接测试(绕开 mihomo)。连不上、而换一条已有代理从墙外能连上 = 落地 IP 被封;这时改节点参数、重导订阅都没用,问题在服务端 IP(见 [[airport-deploy]] 的「连不上的分层诊断」)。
- TUN 回环:开 TUN/fake-ip 时,mihomo 的自动分流路由会把「连代理服务器自己那个入口地址」也吞进 TUN,形成回环超时。用
route-exclude-address 把本次订阅实际节点 server 对应的 IPv4 排除走物理网关:IP 字面量直接排 <ip>/32,域名解析当前 A 记录后逐个排 /32;macOS 上 route get <resolved-ip> 应回到 Wi-Fi 网关而非 198.18.x.x。不要只排域名,也不要维护一份旧的入口 IP 清单,尤其是面向别的用户环境时不能假设他们已有本地兜底脚本。
- 代理域名 DNS 递归:如果 TCP 直连入口成功、
route get 也走物理网关,但 mihomo 日志出现 DoH 经代理组解析节点 server 并最终 dns resolve failed,检查 dns.proxy-server-nameserver。节点域名解析不能依赖同一个尚未建立的代理组。
远程机器复用本地代理
远程服务器下载海外资源慢时,优先用 SSH reverse tunnel 把远端端口转回本地代理:
ssh -f -N -R <remote-port>:127.0.0.1:<local-proxy-port> <remote>
判断闭环不要停在「设置了环境变量」:远端用 curl -x http://127.0.0.1:<remote-port> <url> 验证目标源可达并测速;本地用 external controller 的 GET /connections 或日志确认连接命中预期规则、策略组和出口节点;确定走代理仍慢就切策略组节点重测。对 pip、模型下载、容器拉取等长任务,先确认代理链路和节点质量,再启动大包安装。