v2rayN 7.22.7 加了 VerifyPeerCertByName 支持,但迁移 allowInsecure 不该从“找一个新开关”开始。先看证书是不是公开 CA 签发、SAN 是否包含你填的 serverName。这两项正常,就不需要额外固定。只有名称分离、自签证书、私有 CA 这类配置,才轮到 verifyPeerCertByNamepinnedPeerCertSha256

不看日志的排查都是玄学。这里的日志,指的是 Xray 核心里的 TLS 证书错误,不是 v2rayN 主窗口里泛泛的“运行失败”。

这篇只按三个来源口径写:github.com/2dust/v2rayN 的 7.22.7 发布说明,xtls.github.io 的 Xray TLS 配置文档,以及 github.com/XTLS/Xray-core 的 #5859 社区讨论。#5859 只当排错背景,不当官方承诺。

为什么不是直接把 allowInsecure 打回去?

allowInsecure 的意思很直白:客户端不验证远端 TLS 证书是否可信。Xray 的 TLS 文档已经把它标为 deprecated,并提示改用 pinnedPeerCertSha256。v2rayN 7.22.7 的发布说明也写了两件跟这篇直接相关的事:添加 VerifyPeerCertByName 支持,以及提醒 Xray 将在 2026.8.1 禁用 allowInsecure

所以迁移目标不是“继续让错误消失”。迁移目标是让客户端知道自己正在连的证书是谁。

先把几类现象分清楚:

你看到的现象更可能原因先检查什么
关掉 allowInsecure 后提示 certificate verify failed证书链不被系统信任issuer、系统 CA、是否自签
日志里出现 hostname、SAN、peer cert nameserverName 和证书 SAN 不匹配serverNameverifyPeerCertByName、SAN
同一配置在一台机器能用,另一台不行系统 CA 或时间不同系统时间、根证书包、v2rayN 内核版本
填了 verifyPeerCertByName 仍报错证书链本身不可信是否需要 pinnedPeerCertSha256

这张表的用法很简单:先修证书校验,再看协议字段。反过来排,会把一个 TLS 问题改成三四个混在一起的问题。

迁移路径怎么选?

默认路线只有一个:公开 CA 签发的真实证书。比如证书 SAN 里有 edge.example.com,你的 serverName 也填 edge.example.com,那就让系统 CA 正常验证,不要额外加 pin。

三种迁移选择可以这样判:

证书状态默认动作什么时候换方案
公开 CA 签发,SAN 包含 serverName删除 allowInsecure,保留正常 TLS 校验不需要 verifyPeerCertByName 和 pin
公开 CA 签发,但连接名和证书名有意分离verifyPeerCertByName 为证书 SAN 里的域名证书链不可信时,这个字段救不了
自签证书、私有 CA、临时证书固定 pinnedPeerCertSha256,或把私有 CA 安装进受控设备证书轮换时要同步更新指纹

verifyPeerCertByName 处理的是“用哪个名字验”。pinnedPeerCertSha256 处理的是“我只认这个证书指纹”。两者不是同一种东西。

VerifyPeerCertByName 到底校验什么?

Xray 的 TLS 文档把 verifyPeerCertByName 定义为客户端字段。它会覆盖 serverName 用于证书名称验证,多个域名可以用英文逗号分隔,只要证书 SAN 命中其中一个就算通过名称检查。

这句话里最容易漏掉的是“名称检查”。它不是 allowInsecure 的替身。

举个配置口径:

  • serverName:握手时给远端看的 SNI,也是常规证书校验会用到的名字。
  • verifyPeerCertByName:证书校验时额外指定的名字,适合连接名和证书名分开的特殊部署。
  • pinnedPeerCertSha256:远端证书的 SHA-256 指纹,Xray 文档要求十六进制格式。

如果证书是自签的,系统 CA 不认识它。你只写 verifyPeerCertByName: "localhost",名称可能对了,但信任链还是不对。discussion #5859 里用户遇到的 localhost 证书问题,正好能说明这个坑:日志里看到了证书名,不代表把这个名字填进去就会通过。

怎样用 OpenSSL 看 Subject、SAN 和 sha256?

先用真实连接地址和真实 SNI 抓证书。把下面的 HOSTPORTSNI 改成你的值:

HOST="edge.example.com"
PORT="443"
SNI="edge.example.com"

openssl s_client \
  -connect "${HOST}:${PORT}" \
  -servername "${SNI}" \
  -showcerts </dev/null 2>/dev/null \
  | openssl x509 \
      -noout \
      -subject \
      -issuer \
      -ext subjectAltName \
      -fingerprint \
      -sha256

你要看四行:

subject=CN = edge.example.com
issuer=C = US, O = Example CA, CN = Example CA R3
X509v3 Subject Alternative Name:
    DNS:edge.example.com, DNS:www.example.com
sha256 Fingerprint=E8:E2:D3:87:FD:BF:FE:B3:8E:9C:90:65:CF:30:A9:7E:E2:3C:0E:3D:32:EE:6F:78:FF:AE:40:96:6B:EF:CC:C9

verifyPeerCertByName 要从 SAN 里选,不要只看 subject=CN。现在证书名称校验主要看 Subject Alternative Name。SAN 没有你要的名字,优先重签证书。

如果要填 pinnedPeerCertSha256,Xray 文档接受 SHA-256 指纹的十六进制格式。可以把冒号去掉,转成小写,得到这样的值:

openssl s_client \
  -connect "${HOST}:${PORT}" \
  -servername "${SNI}" \
  -showcerts </dev/null 2>/dev/null \
  | openssl x509 -noout -fingerprint -sha256 \
  | sed 's/^.*=//; s/://g' \
  | tr 'A-F' 'a-f'

输出应接近这种形状:

e8e2d387fdbffeb38e9c9065cf30a97ee23c0e3d32ee6f78ffae40966befccc9

别把这条命令用在错误的端口上。某些 Hysteria、Reality 或特殊传输并不是普通 HOST:443 的 TLS 握手,OpenSSL 看到的可能不是 Xray 实际使用的证书。这种情况要从服务端证书文件算指纹,或使用当前 Xray 工具链提供的 TLS ping/hash 能力。

Xray JSON 里怎么写?

下面是完整的 outbound 片段,只展示 TLS 相关字段。第一种是公开 CA 证书,证书 SAN 里有 origin.example.com,但连接时 serverName 需要填另一个名字的情况:

{
  "outbounds": [
    {
      "tag": "proxy",
      "protocol": "vless",
      "settings": {
        "vnext": [
          {
            "address": "edge.example.com",
            "port": 443,
            "users": [
              {
                "id": "00000000-0000-0000-0000-000000000000",
                "encryption": "none"
              }
            ]
          }
        ]
      },
      "streamSettings": {
        "network": "tcp",
        "security": "tls",
        "tlsSettings": {
          "serverName": "edge.example.com",
          "verifyPeerCertByName": "origin.example.com",
          "fingerprint": "chrome"
        }
      }
    }
  ]
}

第二种是固定证书指纹。这里不要再写 allowInsecure: true

{
  "outbounds": [
    {
      "tag": "proxy",
      "protocol": "vless",
      "settings": {
        "vnext": [
          {
            "address": "edge.example.com",
            "port": 443,
            "users": [
              {
                "id": "00000000-0000-0000-0000-000000000000",
                "encryption": "none"
              }
            ]
          }
        ]
      },
      "streamSettings": {
        "network": "tcp",
        "security": "tls",
        "tlsSettings": {
          "serverName": "edge.example.com",
          "pinnedPeerCertSha256": "e8e2d387fdbffeb38e9c9065cf30a97ee23c0e3d32ee6f78ffae40966befccc9",
          "fingerprint": "chrome"
        }
      }
    }
  ]
}

如果你手里的配置是订阅生成的,先导出实际运行的 Xray JSON 再判断。订阅链接本身不是证据,核心真正读到的 tlsSettings 才是证据。

v2rayN 里改完怎么确认生效?

不要用“网页能打开”当唯一确认。这个信号太粗,DNS、路由、缓存和系统代理都会把结果搅在一起。

按下面顺序看:

  1. v2rayN 版本号是 7.22.7 或更高。
  2. 导出的 Xray JSON 里没有 allowInsecure: true
  3. tlsSettings 里只保留你选择的字段:真实 CA 路线不写额外字段;名称分离写 verifyPeerCertByName;证书固定写 pinnedPeerCertSha256
  4. 启动核心后,日志里不再出现 allowInsecurecertificateunknown authoritypeer cert invalid 这类 TLS 错误。
  5. 只在 TLS 错误消失后,再看延迟测试、路由命中和应用连接。

如果第 4 步还失败,回到 OpenSSL 输出。把 SAN、issuer、sha256 指纹和 JSON 里的 serverName 摆在一起看,通常比反复导入配置快。

discussion #5859 能说明什么,不能说明什么?

Xray-core discussion #5859 是一个社区排错问题。用户的配置里有 allowInsecure,日志里出现证书名称和 verifyPeerCertByNamepinnedPeerCertSha256 相关错误,并追问特殊传输下怎么拿到原始证书。

它能说明两点:

  • verifyPeerCertByName 不是万能开关,名称对了也可能因为证书链或指纹问题失败。
  • 特殊传输、混淆层、非标准端口会让“从远端抓证书”这件事变得不直观。

它不能说明两点:

  • 不能把提问里的写法当成 Xray 官方推荐配置。
  • 不能把“希望日志打印 sha256”当成已经承诺的功能。

社区问题适合当排错背景,不适合当迁移依据。真正该跟的是 v2rayN 发布说明和 Xray TLS 文档。

哪些旧配置别顺手保留?

迁移时最容易留下三个尾巴。

第一,allowInsecure: true。如果核心已经提示这个功能迁移到证书固定,就不要在同一份配置里继续保留它。你要么回到真实 CA 校验,要么明确 pin 证书指纹。

第二,把 serverNameverifyPeerCertByNameaddress 写成三个互不相干的域名。除非你知道证书为什么这样部署,否则先让三者一致,再逐个拆开。

第三,把 SHA-256 指纹当成永久不变。证书续签、重签、换 CA、中间证书调整,都可能让指纹变化。固定指纹后,证书轮换就变成一次配置变更,不是后台自动完成的事。

最后留一个简单的回滚线:保留迁移前的 JSON,但不要回滚到 allowInsecure: true 当长期方案。正确的回滚应该是恢复上一张有效证书、上一条匹配 SAN 的 serverName,或上一枚确认过的 pinnedPeerCertSha256

同一类 TLS 排查可以接着看 Trojan TLS 证书域名。如果你还在核对客户端入口,先看 v2rayN 客户端;需要服务端配置背景,再看 Xray-core 部署指南