Mihomo v1.19.27 的 github.com Release notes 写明,根级 global-client-fingerprint 不再是可靠写法。看到启动警告或发现字段失效时,不要整份配置重做;把原来的值挪到每个需要 TLS 指纹的 proxies 节点里,再重载配置看日志。

这个变化最容易坑旧订阅模板。以前一行全局 chrome 能覆盖一批节点,现在要逐个节点写 client-fingerprint: chrome。订阅转换器可能会补,也可能完全不补,最终以客户端实际加载的 YAML 为准。

启动日志里看到什么才算中招?

典型信号不是节点列表为空,而是配置能导入、内核能启动,但启动阶段出现旧字段提示,或者 Reality / TLS 节点握手表现突然变得不一致。先看日志,不看日志的排查都是玄学。

日志里重点看三类信号:第一,是否出现旧字段相关提示;第二,配置是否加载到你刚改过的 profile;第三,TLS / Reality 节点是否仍有握手失败。不同 GUI 的日志前缀和文案会变化,不要只按某一句固定文本搜索。

只看到 handshake failure 不能直接断定是指纹字段。它也可能是 servername、Reality public-keyshort-id、服务端时间或目标站问题。这里的判断点是:配置里还存在 global-client-fingerprint,并且代理节点内部没有对应的 client-fingerprint

旧字段到底迁到哪里?

迁移目标很窄:从根级字段迁到代理节点字段。Mihomo v1.19.27 Release notes 写的是移除 global-client-fingerprint,改为在 proxy 上直接设置 client-fingerprint;官方 General 文档也把全局 TLS 指纹标成弃用。

下面这张表先把改动范围定死,别把 DNS、规则组和 provider 一起改了。

旧位置或旧习惯新位置先改哪些节点不要顺手改什么
根级 global-client-fingerprint: chrome每个代理里的 client-fingerprint: chromeVMessVLESSTrojanAnyTLSrulesproxy-groupsdns
订阅模板只输出一次全局字段模板循环每个 proxy 时输出字段使用 TLS / Reality 的节点节点名和策略组引用
GUI 导入后看不到旧字段导出最终 YAML 再查导入后的实际配置文件不要只看订阅原文
多端共用旧订阅每端确认内核版本和导出 YAML已升级到 v1.19.27 的客户端不要假设所有端行为一致

Mihomo TLS 代理配置页列出的 client-fingerprint 可选值包括 chromefirefoxsafariiosandroidedge360qqrandom。排障时先沿用旧全局字段的原值,不要趁迁移顺手把 chrome 改成 random

YAML before/after 应该怎么改?

先备份原文件。Clash Verge Rev 常见 profile 在 ~/.config/clash-verge-rev/profiles/,Mihomo Party、OpenClash、Docker 挂载目录按你自己的客户端路径找。下面示例只展示和迁移有关的字段。

旧写法通常是根级一个全局字段,节点里没有 client-fingerprint

# before: config.yaml
mixed-port: 7890
mode: rule
log-level: info
global-client-fingerprint: chrome

proxies:
  - name: "vless-reality-01"
    type: vless
    server: example.com
    port: 443
    uuid: 00000000-0000-0000-0000-000000000000
    network: tcp
    tls: true
    servername: www.example.com
    reality-opts:
      public-key: "PUBLIC_KEY"
      short-id: "SHORT_ID"

  - name: "trojan-tls-01"
    type: trojan
    server: trojan.example.com
    port: 443
    password: "PASSWORD"
    sni: trojan.example.com

新写法是删掉根级 global-client-fingerprint,把同一个值写到对应代理内部:

# after: config.yaml
mixed-port: 7890
mode: rule
log-level: info

proxies:
  - name: "vless-reality-01"
    type: vless
    server: example.com
    port: 443
    uuid: 00000000-0000-0000-0000-000000000000
    network: tcp
    tls: true
    servername: www.example.com
    client-fingerprint: chrome
    reality-opts:
      public-key: "PUBLIC_KEY"
      short-id: "SHORT_ID"

  - name: "trojan-tls-01"
    type: trojan
    server: trojan.example.com
    port: 443
    password: "PASSWORD"
    sni: trojan.example.com
    client-fingerprint: chrome

同一件事用 diff 看更清楚:

-global-client-fingerprint: chrome
-
 proxies:
   - name: "vless-reality-01"
     type: vless
     server: example.com
@@
     tls: true
     servername: www.example.com
+    client-fingerprint: chrome
     reality-opts:
       public-key: "PUBLIC_KEY"
       short-id: "SHORT_ID"
@@
   - name: "trojan-tls-01"
     type: trojan
     server: trojan.example.com
@@
     password: "PASSWORD"
     sni: trojan.example.com
+    client-fingerprint: chrome

YAML 缩进不能错。client-fingerprint 要和 servernametlsreality-opts 同级,而不是塞进 reality-opts 下面。

哪些 proxy 需要补,哪些不用动?

官方 TLS 代理配置页把 client-fingerprint 归在 TLS 配置下,并说明它用于 VMessVLESSTrojanAnyTLS。所以迁移时只处理这类会用到 TLS 客户端指纹的代理。

proxy 类型是否优先补 client-fingerprint判断口径
vless + tls: true / RealityReality 和 TLS 握手对字段更敏感,先补
trojanTrojan 强依赖 TLS,旧全局值应迁进去
vmess + tls: true只有 TLS 节点需要补,非 TLS VMess 不硬加
anytls官方列在适用协议里
sssocks5http通常不用不是这次字段迁移的目标
DIRECTREJECT、内置策略不用它们不是出站代理节点参数

如果你有 proxy-providers,不要只改主配置里的 proxies。provider 拉下来的远程 YAML 里也可能包含旧节点结构。客户端最终加载的是合并后的配置,主文件干净不代表 provider 内容也干净。

订阅转换器会不会自动处理?

不要承诺它会。订阅转换器有三层差异:转换器程序是否知道 v1.19.27 的变化,模板是否把字段写到每个 proxy,GUI 是否在导入后又做了一次兼容处理。任意一层没更新,最终 YAML 仍可能缺字段。

最小检查办法是导出或找到客户端实际加载的 YAML,然后搜索两个字段:

grep -n 'global-client-fingerprint\|client-fingerprint' ./config.yaml

你想看到的是:没有 global-client-fingerprint,需要 TLS 指纹的节点下面有 client-fingerprint。如果只看到旧字段,说明转换器没迁;如果两个字段都看不到,要回到订阅源或转换模板确认指纹原本是不是就没下发。

迁移后怎么确认真的生效?

先做配置层检查,再做运行层检查。不要一上来测速,测速只能证明某个连接当时通了,不能证明字段被内核读取。

配置层检查:

grep -n 'global-client-fingerprint' ./config.yaml
grep -n 'client-fingerprint' ./config.yaml

第一条最好没有输出。第二条应该在目标节点附近出现。然后重载配置,打开客户端日志,把 log-level 临时调到 info 或短时间 debug

运行层看两件事:旧字段提示是否消失,目标节点是否完成一次明确的 HTTPS 访问。日志里要能对应到你刚迁移的节点名、规则命中或出站 tag;如果只能看到「连接失败」四个字,证据还不够。

若警告消失但连接仍失败,继续查 servername、Reality public-keyshort-id、端口和服务端日志;不要把所有握手失败都归到 client-fingerprint

回滚时保留哪一份配置?

回滚不要把 global-client-fingerprint 加回去。更稳的办法是保留两份文件:一份是升级前原始 YAML,另一份是只做过字段迁移的新 YAML。新 YAML 失败时,用 diff 看是不是误动了节点参数。

diff -u ./config.before-v11927.yaml ./config.after-v11927.yaml

正常 diff 应该只出现一类变化:根级旧字段被删除,目标 proxy 增加 client-fingerprint。如果 diff 里还出现 uuidpasswordservernamereality-optsproxy-groups 变化,先撤回这些无关改动,再重新加载。一次只改一个变量,排错才不会散。

相关阅读

本文核对的是 Mihomo v1.19.27、wiki.metacubex.one 的官方 General 配置页和 TLS 代理配置页。移动端 GUI、OpenWrt 插件和第三方订阅转换器可能有自己的缓存与模板层,遇到不一致时,以最终加载到 Mihomo 内核的 YAML 和启动日志为准。