一、先按报错文本分类,再决定查哪一层

证书报错是浏览器对 TLS 握手结果的转述,不是 Clash 的输出。Chrome、Edge 与 Firefox 已经把失败环节写进了报错文本,先完整抄下这句话,再对照下表决定查哪一层,比反复开关代理有效得多。

Chrome / Edge 证书报错文本与优先排查方向
报错文本含义优先排查
NET::ERR_CERT_DATE_INVALID证书不在有效期内系统时间、根证书有效期
NET::ERR_CERT_AUTHORITY_INVALID签发者不在本机信任列表中间证书缺失、本地拦截软件
NET::ERR_CERT_COMMON_NAME_INVALID证书域名与访问域名不一致DNS 解析结果、hosts 映射
NET::ERR_CERT_REVOKED证书已被吊销目标站点侧问题
SSL_ERROR_BAD_CERT_DOMAIN(Firefox)域名不匹配,同上DNS 解析与 SNI

Firefox 使用自带的 NSS 证书库,不读取系统根证书存储。系统里装了企业网关或抓包工具的根证书时,Chrome 能正常打开页面,Firefox 仍可能报 SEC_ERROR_UNKNOWN_ISSUER。遇到「同一域名两个浏览器表现不同」,先怀疑证书存储,而不是代理链路。

命令行能更快拿到细节,两个命令就够:

curl -vI https://example.com --max-time 8
openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null

curl 返回 SSL certificate problem: unable to get local issuer certificate,说明证书链不完整或本机缺少对应根证书;返回 certificate has expired,则是时间或有效期问题。这两条信息比浏览器弹窗更接近根因。

先用一个动作划清边界

退出客户端、关闭系统代理,用同一浏览器访问同一域名。关闭代理后恢复正常,问题在代理链路或节点;关闭后仍然报错,问题在本机证书存储或站点本身,与 Clash 无关。这一步做完,后面就不会白花时间。

二、第一步:核对系统时间与证书有效期

证书的有效期由 notBefore 与 notAfter 两个时间点界定,系统时间只要落在区间之外,握手就会失败。笔记本长期休眠、双系统来回切换、虚拟机快照回滚,都会让系统时钟漂移几分钟到几天,而用户往往察觉不到。

  • Windows:设置 → 时间和语言 → 日期和时间 → 打开「自动设置时间」,再点「立即同步」。命令行用 w32tm /resync 强制对时,w32tm /query /status 查看当前时间源。
  • macOS:系统设置 → 通用 → 日期与时间 → 打开「自动设置日期与时间」。终端执行 sudo sntp -sS time.apple.com 可手动校时。
  • Linux:timedatectl status 查看 NTP 同步状态,sudo systemctl restart systemd-timesyncd 重启对时服务。

时间正确却仍报 ERR_CERT_DATE_INVALID,就要看根证书本身。DST Root CA X3 于 2021-09-30 到期,当时大量旧 Android 设备与旧版 OpenSSL 客户端出现连锁报错,原因是服务端仍在下发指向该根的交叉签名链。查看本机根证书列表的入口:Windows 运行 certlm.msc → 受信任的根证书颁发机构 → 证书;macOS 打开「钥匙串访问」→ 系统 → 证书;Linux 查看 /etc/ssl/certs 目录。

判定标准很简单:同一域名换一台时间正常的设备访问正常,说明问题在本机时间或证书存储,与节点无关,不必继续往下查。

三、第二步:检查根证书链与本地拦截软件

中间证书缺失属于服务端配置问题,表现却常常像客户端问题。服务器只下发站点证书、不下发中间证书时,浏览器会尝试用缓存的中间证书或证书里的 AIA 扩展补齐;换了浏览器、清了缓存之后补齐失败,就会报 ERR_CERT_AUTHORITY_INVALID。

openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null 2>/dev/null | grep -c "BEGIN CERTIFICATE"

输出为 1,说明服务端只返回了站点证书,链不完整;正常情况应返回 2 到 3。这类问题只能由站点侧补发中间证书解决,客户端改配置没有意义。

本地拦截类软件是第二个高频来源。企业网关、带网页防护的安全软件、抓包工具(Charles、Fiddler、mitmproxy)会在本机安装一张自签根证书,用它重签你访问的每一个站点证书。这张根证书装在系统存储里,Chrome 与 Edge 信任它,访问一切正常;Firefox、Java 应用、部分 Electron 客户端使用各自的证书库,就会报错。逐项核对的位置:

  • Windows:certlm.msc → 受信任的根证书颁发机构 → 证书,按「颁发者」列排序,找非公共 CA 的条目(企业域名、安全软件厂商名)。
  • macOS:钥匙串访问 → 系统 → 证书,检查是否存在来源不明的自签根证书。
  • Firefox:设置 → 隐私与安全 → 证书 → 查看证书 → 证书颁发机构,与系统列表逐条比对。

不要用跳过校验的方式绕过报错

curl 的 --insecure、浏览器的 ignore-certificate-errors 启动参数,都属于把检测能力直接关掉。问题会从看得见的报错变成看不见的风险,排查线索也一并消失。

这里需要明确一点:Clash 与 mihomo 内核只做 TCP/UDP 转发和规则分流,不参与 TLS 握手,也不解密 HTTPS 流量,代理链路本身不会替换证书。除非你额外挂了 MITM 类工具,否则把证书报错归因于内核,方向从一开始就错了。

四、第三步:代理链路、DNS 与分流设置

域名解析到错误 IP,是证书报错的第三个来源。证书的 CN 与 SAN 字段绑定的是域名,浏览器拿到一张不属于该域名的证书,就会报 ERR_CERT_COMMON_NAME_INVALID。常见触发场景有三个:DNS 被污染后返回了错误地址;hosts 里手写的映射已经过期;把 fake-ip 地址当成真实地址填进了别的工具。

dns:
  enable: true
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16
  nameserver:
    - https://223.5.5.5/dns-query

fake-ip 模式下,mihomo 会给域名分配 198.18.0.1/16 段内的虚拟地址,这个映射只存在于客户端内部,连接建立时会被还原成域名,不参与 TLS 校验。真正会出问题的是把 198.18.x.x 写进 hosts 或某个不走代理的工具,域名信息丢失之后,证书自然对不上。

分流规则也会间接引发证书报错。某个域名被规则判定为直连,而当前网络对该域名做了劫持,返回的就是伪造证书。排查方式:在 Clash Verge 的「连接」页面找到这条连接,看命中的规则与出口节点,再把这个域名切到代理节点重试。切换后恢复正常,说明问题在直连出口,不在证书。

系统代理没覆盖到的情况要单独区分。部分应用不读取系统代理设置,流量走直连,被阻断时抛的是连接重置或超时,不是证书错误,把这两类报错混在一起查会绕远路。确认端口一致:mixed-port 常见 7890,Clash Verge 系列默认 7897,浏览器扩展与系统代理需要指向同一个端口。

TUN 模式在网卡层接管流量,不依赖应用是否支持代理,但它同样不解密 TLS,证书校验仍然在浏览器侧完成。TUN 模式下出现证书报错,优先查 DNS 与分流规则,而不是反复开关 TUN 本身。

五、按顺序执行的排查清单

  1. 记录完整报错文本、域名与发生时间,确认是持续性报错还是偶发。
  2. 退出客户端并关闭系统代理,用同一浏览器重试,判断问题是否与代理有关。
  3. 校准系统时间,重启浏览器后再访问一次。
  4. 执行 openssl s_client -connect 域名:443 -servername 域名 -showcerts,确认证书链完整、有效期覆盖当前时间。
  5. 检查系统根证书列表,排除企业网关或安全软件安装的拦截证书;Firefox 需单独核对一次。
  6. 在客户端「连接」页面确认该域名命中的规则、出口节点与 DNS 解析结果。
  7. 把该域名切到另一节点或另一策略组,观察报错文本是否发生变化。
  8. 换一个网络(例如手机热点)交叉验证,区分本地网络问题与节点侧问题。

清单里第 2 步和第 4 步的性价比最高:一个负责划清责任边界,一个直接给出证书链的实际状态。多数案例走到这里就能定位。

六、几种常见误判

  • 换节点能解决证书报错。节点只转发字节流,证书由目标站点提供;换节点后仍报同一错误,基本可以排除节点。
  • TUN 模式会改变证书校验。不会,TUN 改变的是流量接管方式,TLS 校验依旧在浏览器侧完成。
  • 更新订阅能修复证书错误。订阅内容只影响节点列表与规则,不会写入系统证书存储。
  • 清理浏览器缓存就能解决。只有在中间证书缺失、且此前依赖缓存补齐的情况下偶尔有效,不属于稳定解法。
  • 换个客户端就好了。主流客户端共用 mihomo 内核与同一套系统代理设置,更换客户端并不改变 TLS 校验路径。

把顺序固定下来:报错文本 → 系统时间 → 根证书链 → 代理与 DNS → 节点。前两步能覆盖大部分案例,把内核当成第一嫌疑人,通常只是多花时间。