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-key、short-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: chrome | VMess、VLESS、Trojan、AnyTLS | rules、proxy-groups、dns |
| 订阅模板只输出一次全局字段 | 模板循环每个 proxy 时输出字段 | 使用 TLS / Reality 的节点 | 节点名和策略组引用 |
| GUI 导入后看不到旧字段 | 导出最终 YAML 再查 | 导入后的实际配置文件 | 不要只看订阅原文 |
| 多端共用旧订阅 | 每端确认内核版本和导出 YAML | 已升级到 v1.19.27 的客户端 | 不要假设所有端行为一致 |
Mihomo TLS 代理配置页列出的 client-fingerprint 可选值包括 chrome、firefox、safari、ios、android、edge、360、qq、random。排障时先沿用旧全局字段的原值,不要趁迁移顺手把 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 要和 servername、tls、reality-opts 同级,而不是塞进 reality-opts 下面。
哪些 proxy 需要补,哪些不用动?
官方 TLS 代理配置页把 client-fingerprint 归在 TLS 配置下,并说明它用于 VMess、VLESS、Trojan、AnyTLS。所以迁移时只处理这类会用到 TLS 客户端指纹的代理。
| proxy 类型 | 是否优先补 client-fingerprint | 判断口径 |
|---|---|---|
vless + tls: true / Reality | 是 | Reality 和 TLS 握手对字段更敏感,先补 |
trojan | 是 | Trojan 强依赖 TLS,旧全局值应迁进去 |
vmess + tls: true | 是 | 只有 TLS 节点需要补,非 TLS VMess 不硬加 |
anytls | 是 | 官方列在适用协议里 |
ss、socks5、http | 通常不用 | 不是这次字段迁移的目标 |
DIRECT、REJECT、内置策略 | 不用 | 它们不是出站代理节点参数 |
如果你有 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-key、short-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 里还出现 uuid、password、servername、reality-opts、proxy-groups 变化,先撤回这些无关改动,再重新加载。一次只改一个变量,排错才不会散。
相关阅读
本文核对的是 Mihomo v1.19.27、wiki.metacubex.one 的官方 General 配置页和 TLS 代理配置页。移动端 GUI、OpenWrt 插件和第三方订阅转换器可能有自己的缓存与模板层,遇到不一致时,以最终加载到 Mihomo 内核的 YAML 和启动日志为准。