网站接入 Cloudflare 后出现 525 SSL handshake failed 或 526 Invalid SSL certificate,通常要检查的是 Cloudflare 到 VPS 源站这一段 HTTPS。浏览器地址栏能显示正常的 Cloudflare 证书,并不代表源站的证书和 TLS 配置也正确。
本文面向通过 Cloudflare 代理访问的普通 HTTPS 网站,以 Linux VPS、Nginx、curl 和 OpenSSL 为例。先分清错误类型,再核对实际源站、带域名测试 TLS、修复证书或握手配置,最后验证 Cloudflare 回源恢复。Cloudflare Tunnel、Spectrum 和 Zero Trust Gateway 的连接方式不同,应同时参考对应产品的排障文档。
| 错误 | 失败位置 | 优先看什么 |
|---|---|---|
525 SSL handshake failed | Cloudflare 与源站的 TLS 握手 | HTTPS 监听、SNI、协议/加密套件、连接重置、客户端证书要求 |
526 Invalid SSL certificate | Cloudflare 验证源站证书 | 有效期、域名匹配、签发机构、证书链、实际返回的证书 |
在普通代理网站场景中,525 可能发生于 Full 或 Full (strict) 模式;526 通常与 Full (strict) 的源站证书验证有关。两者都可能涉及证书配置,但修复顺序不同。具体定义见 Cloudflare 525 文档与 526 文档。
记住网站有两段连接:访客 → Cloudflare → VPS 源站。边缘证书负责第一段,源站证书负责第二段。重新上传一个边缘证书,未必能解决源站错误。
先记下出错的完整域名、时间、错误码和页面显示的 Ray ID;如果是间歇故障,也记录正常与失败的时间段。然后在 Cloudflare 控制台核对:
- 当前 SSL/TLS 加密模式,以及是否有规则覆盖该域名的设置。
- DNS 记录中配置的源站地址,是否仍对应当前 VPS。
- 是否配置了多个 A/AAAA 地址、负载均衡源站或自定义回源端口。
- 是否有 Origin Rules 等设置改变回源 Host、SNI 或目标地址。
代理开启时,公开 DNS 查询通常看到的是 Cloudflare 地址。 不要把 dig example.com 查到的边缘 IP 当作 VPS 源站 IP。源站地址应从控制台配置和 VPS 实例信息核对。
多台源站中只有一台证书过期,也会造成“刷新几次就恢复”的假象。应逐个检查所有实际可能接收回源请求的地址,IPv4 与 IPv6 都要与监听配置一致。
以下示例中的 example.com 和 203.0.113.10 是占位值,分别替换成出错域名和实际源站 IP。用 curl 的 --resolve 临时指定地址,同时保留 URL 中的域名:
curl -v --connect-timeout 5 --max-time 15 --noproxy '*' \
--resolve example.com:443:203.0.113.10 \
https://example.com/ -o /dev/null
这样会把请求发给指定 IP,同时按 example.com 进行 TLS SNI、证书主机名检查和 HTTP Host 处理;--noproxy '*' 避免测试被本地 HTTP 代理转发。它不修改 DNS 或系统 hosts 文件,参数含义见 curl 官方手册。
只运行 curl https://203.0.113.10,或只增加一个 HTTP Host 请求头,可能无法选中正确的 TLS 虚拟主机。证书通常签给域名,不能用 IP 访问时的域名不匹配直接判断 Cloudflare 回源也有问题。
根据输出继续判断:
| 直连结果 | 下一步 |
|---|---|
| 连接拒绝或超时 | 核对监听、端口、防火墙和测试来源是否允许 |
握手阶段断开、wrong version number 等 | 检查 443 上是否真的是 TLS 服务,以及协议与反向代理映射 |
| 证书过期、域名不匹配或链验证失败 | 进入 526 证书排查;Origin CA 要用下面的专门方法理解 |
| TLS 验证成功并收到 HTTP 响应 | 这条测试路径的 TLS 已工作,再看 Cloudflare 回源路径与规则 |
HTTP 403、404 或应用 500 不等于 TLS 握手失败。先区分证书验证、TLS 连接和业务 HTTP 响应三个阶段。
外部电脑直连被拒绝可能是预期防护效果。不要为了测试把源站永久开放给所有 IP。可以从 VPS 本机测试实际监听地址,或短暂允许可信管理 IP;本机测试能帮助确认服务配置,但不能证明 Cloudflare 的网络路径也通。
如果源站启用了 Authenticated Origin Pulls(AOP),它可能要求客户端证书,普通 curl 没有对应证书时会被拒绝。这时应核对 Cloudflare 的 AOP 配置、源站客户端 CA 与相关日志,而不是把“直连失败”一律解释成 HTTPS 坏了。AOP 的作用见官方说明。
在 VPS 上读取监听、配置校验和错误日志:
sudo ss -lntp
sudo nginx -t
sudo tail -n 100 /var/log/nginx/error.log
sudo journalctl -u nginx -b --no-pager -n 100
端口不一定是默认 443,以实际回源规则为准。容器部署也应确认公网端口映射到的是 TLS 终止服务,而不是只接受 HTTP 的应用端口。使用 Caddy、Apache 或其他代理时,查看对应服务日志;不要把 Nginx 命令套到并未运行 Nginx 的机器上。
重点把源站日志与报错时间对应起来:
SSL_do_handshake() failed附近是否有协议、加密套件或客户端证书错误。- 是否发生连接重置,或只有特定来源、域名、监听地址出现错误。
- 证书和私钥能否读取、是否配对,配置是否刚修改但未加载成功。
- 是否把 HTTP 服务误放在 HTTPS 回源端口。
查看 Nginx 生效配置中与 TLS 有关的字段:
sudo nginx -T 2>&1 | grep -E 'listen|server_name|ssl_certificate|ssl_protocols|ssl_ciphers|ssl_verify_client|ssl_client_certificate'
确认对应 server_name 的 HTTPS server 块会被选中。多域名共用一个 IP 时,SNI 会影响返回哪张证书;错误的默认站点、域名覆盖或监听配置,都可能让回源得到错误证书。TLS 虚拟主机机制见 Nginx HTTPS 配置说明。
不要通过开启过时 TLS 协议、清空加密套件限制或关闭客户端证书认证来长期消除错误。先确认具体不兼容项,再使用与当前服务版本、Cloudflare 回源要求匹配的 TLS 配置。
Full (strict) 要求源站证书在有效期内、由受信任的公开 CA 或 Cloudflare Origin CA 签发,并覆盖请求或目标主机名。相关要求见 Full (strict) 文档。
用 OpenSSL 带 SNI 查看源站实际发送的证书与握手信息:
timeout 15 openssl s_client \
-connect 203.0.113.10:443 \
-servername example.com -showcerts </dev/null
-showcerts 展示服务器发来的证书,不表示完整信任验证已经成功。针对使用公开 CA 证书的常规源站,可以进一步做主机名与信任验证:
timeout 15 openssl s_client \
-connect 203.0.113.10:443 -servername example.com \
-verify_hostname example.com -verify_return_error </dev/null
OpenSSL 默认可能显示验证错误后仍继续握手;-verify_return_error 让验证失败中止。参数含义见 OpenSSL s_client 文档。本机信任库与 Cloudflare 的信任判断并不完全相同,所以这项结果要与证书类型、控制台设置和实际回源结果一起看。
如果使用 Certbot 管理证书,也可以查看本地证书详情:
sudo certbot certificates
sudo openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem \
-noout -subject -issuer -dates -ext subjectAltName
重点核对:
notBefore、notAfter是否覆盖当前时间。- SAN 是否包含实际出错域名;
*.example.com不覆盖根域example.com,也不覆盖a.b.example.com。 - 是否签给了另一个站点,或者证书文件更新后服务仍返回旧证书。
- 是否提供了所需中间证书;证书链是否来自对应签发机构。
本地文件新,不代表公网监听已经使用它。应比较文件详情与源站实际发送的证书,尤其检查多个 server 块、多个节点和容器挂载目录。
对于 Certbot 常规目录,检查现有 HTTPS server 块中的这两个字段是否指向相应文件:
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
这是现有 server 块中的字段示例,不是需要覆盖整个站点的配置模板。对于其他 CA,按该 CA 提供的正确顺序准备叶证书与中间链。Nginx 要求服务器证书在组合文件中位于中间证书之前,详见 SSL certificate chains。
不要把互不相关的证书随意拼起来,也不要把私钥放进证书链文件。私钥应保留在源站受限文件中,不要粘贴到公开日志或排障截图里。
Cloudflare Origin CA 证书主要用于 Cloudflare 与源站之间的连接,可以满足 Full (strict),但一般浏览器或本机 curl 默认不会信任它。关闭代理、暂停 Cloudflare 或直接访问源站后出现 unknown CA、NET::ERR_CERT_AUTHORITY_INVALID,可能正是这一信任范围导致的。官方说明见 Origin CA与故障排查。
若需要从可信管理机验证这张证书,可从 Cloudflare 官方 Origin CA 文档取得与签发类型对应的根证书,保存为本地文件后明确指定:
curl -v --connect-timeout 5 --max-time 15 --noproxy '*' \
--cacert /path/to/cloudflare-origin-ca-root.pem \
--resolve example.com:443:203.0.113.10 \
https://example.com/ -o /dev/null
把示例 CA 文件路径替换为已核对来源的文件。--cacert 指定的是用于信任验证的 CA 公钥证书,不是网站私钥,也不是 AOP 的客户端认证 CA。
curl -k 会跳过服务器证书验证,不能据此证明 526 已修复。若网站还需要绕过 Cloudflare 直接供浏览器访问,源站应使用公开受信任的证书,并按实际入口部署;不要只为消除本机警告就改变整个站点的加密模式。
修改前记录原来的 SSL/TLS 模式、相关规则、证书路径和配置文件。备份实际站点文件,以下只是常见路径示例:
sudo cp -a /etc/nginx/sites-available/example.com \
/etc/nginx/sites-available/example.com.backup.$(date +%Y%m%d%H%M%S)
修正证书路径、链或 TLS 配置后,校验通过才 reload:
sudo nginx -t && sudo systemctl reload nginx
如果校验失败,先修正或恢复配置,别强行重启。证书续期问题应从续期任务与证书签发流程解决,不能靠长期关闭 Full (strict) 的验证。Cloudflare 官方把从 strict 切到 Full 列为一种 526 临时绕过方法,但这会放宽源站身份验证;它只能作为明确接受风险的短期恢复选择,不代表证书故障已经修好。
永久修复目标是:正确源站能完成 TLS 握手、证书满足所用加密模式、Cloudflare 回源与业务都正常。不要把切换 Flexible、关闭代理或只看到页面缓存当成完成验收。
重新测试每个实际源站的域名、端口与证书;再访问 Cloudflare 代理后的公网域名。选择一个确认不会只由旧缓存提供的测试地址,并把访问时间与源站日志对应起来。查看 HTTP 状态、登录或 API 等关键业务是否正常,而不只是首页能否打开。
如果是间歇故障,检查多台源站、A/AAAA 和负载均衡池的证书是否一致;单个节点成功不能证明全部回源都正常。保留原错误时间、Ray ID、具体失败日志与修复记录,方便继续定位。
- 实际错误变成 521/522:源站监听、防火墙与回源连接排查。
- 源站证书到期或续期没生效:Let’s Encrypt、Certbot 与 DNS-01 续期排查。
- 配置修改后无法加载:Nginx 配置校验与 reload failed 排查。
处理 525/526 时,先确认哪一段 TLS、哪一个源站、哪张实际证书出了问题,再修正对应配置。这样既能恢复网站,也能保持源站身份验证有效。
