平台和 DevOps
Error 525 SSL handshake failed:Cloudflare 回源握手失败的修法
Error 525: SSL handshake failedCloudflare 525 的意思是:Cloudflare 连上了你的源站,但和源站之间的 TLS 握手没有完成。 访客到 Cloudflare 的 HTTPS 连接没问题,坏的是 Cloudflare 回源这一段,在发出任何 HTTP 请求之前就失败了。只有加密模式为 Full 或 Full (strict) 时才会出现这个错误,因为只有这两种模式下 Cloudflare 才会用 HTTPS 连源站。
525 坏在哪一段
525 坏在 Cloudflare 到源站这一段。套了 Cloudflare 代理(小黄云)的网站有两条独立的 TLS 连接:
| 连接 | 由谁负责 | 出问题时的报错 |
|---|---|---|
| 访客 → Cloudflare 边缘 | Cloudflare 的边缘证书 | 浏览器报错,比如 ERR_SSL_VERSION_OR_CIPHER_MISMATCH |
| Cloudflare → 源站 | 你服务器上的 TLS 配置 | 525(握手失败)或 526(证书不被认可) |
如果 Cloudflare 连不上源站,会报别的代码,比如 521(源站宕机)、522(连接超时)。看到 525,说明 TCP 已经连上了,是上面的 TLS 层失败。
常见原因(按出现频率排序)
525 有 6 种原因,最常见的是源站 443 端口没有可用的 TLS。
1. 源站 443 端口没有可用的 TLS
最常见的情况:网站当初按 Flexible 模式搭的,源站只跑 HTTP,后来有人把加密模式改成了 Full。此时源站 443 要么跑的是明文 HTTP,要么压根没配证书。Cloudflare 官方列的第一条原因就是“源站没有安装有效的 SSL 证书”。
确认方法:绕过 Cloudflare 直连源站 IP,同时带上真实域名作 SNI:
openssl s_client -connect 203.0.113.10:443 -servername example.com -brief </dev/null
出现 wrong version number 或 packet length too long,说明 443 上跑的是明文 HTTP;连接被重置或提示 no peer certificate available,说明这个域名没有加载证书。
2. 源站没有 Cloudflare 所请求域名的证书
Cloudflare 回源时会在 SNI 里带上访客访问的域名。源站如果只给别的域名配了证书,或者默认站点设置了拒绝未知域名(Nginx 的 ssl_reject_handshake on;),握手就会失败。上面的命令要对每个开了代理的域名都跑一遍,www 也别漏。
3. 加密套件没有交集
Cloudflare 公开了回源时提供的套件清单:TLS 1.3 支持三个标准 AEAD 套件;TLS 1.2 提供 ECDHE-ECDSA、ECDHE-RSA 的 AES-GCM 套件,ECDHE-RSA-AES-SHA,以及纯 RSA 的 AES 套件,没有 DHE,也没有 CHACHA20。源站如果被“加固”成只开 TLS 1.2、只允许 CHACHA20 或 DHE,就和 Cloudflare 谈不拢。用下面的命令看源站接不接受某个套件:
openssl s_client -connect 203.0.113.10:443 -servername example.com -tls1_2 \
-cipher 'ECDHE-RSA-AES128-GCM-SHA256' -brief </dev/null
4. 443 端口被防火墙过滤或重置
阿里云、腾讯云的安全组,宝塔的系统防火墙,或者入侵防护设备,如果放行了 TCP 但又掐断了 TLS 流量,表现就是 525 而不是 522。fail2ban 这类按请求量封 IP 的工具,在没配置真实 IP 时看到的全是 Cloudflare 的 IP,很容易把 Cloudflare 自己封掉,造成时好时坏的 525。
5. 源站要求客户端证书
源站在 TLS 层强制要求双向 TLS(比如 Apache 的 SSLVerifyClient require),但 Cloudflare 那边没开 Authenticated Origin Pulls,Cloudflare 拿不出客户端证书,源站就会中止握手。Nginx 的行为不一样:ssl_verify_client on; 时它会先完成握手,再返回 HTTP 400 错误,所以不会表现为 525。
6. 高负载下偶发失败
525 时有时无时,Cloudflare 建议把出错时间点和源站错误日志对照。Nginx 日志里重点找 SSL_do_handshake() failed 和 no shared cipher,或者 TLS 终止程序崩溃重启的记录。
怎么修
修法是让源站在 443 端口完成 TLS 握手:装好证书,按 SNI 返回正确的站点,开启 Cloudflare 支持的协议和套件。
先给源站装证书。 Full 模式下任何证书都行(包括自签名);Full (strict) 则需要公共信任的证书,或者 Cloudflare 签发的 Origin CA 证书,后者的做法见 Cloudflare 源站证书教程。也可以用 Let's Encrypt,或者阿里云、腾讯云的免费证书。
Nginx 示例:
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name example.com www.example.com;
ssl_certificate /etc/ssl/example.com/fullchain.pem;
ssl_certificate_key /etc/ssl/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
}
宝塔面板: 在网站设置的“SSL”里粘贴证书和私钥并保存,宝塔会自动生成 443 监听。注意不要勾“强制 HTTPS”之后又把 Cloudflare 切回 Flexible,否则会出现重定向循环。
Apache: 启用 mod_ssl,新增 <VirtualHost *:443>,写上 SSLEngine on、SSLCertificateFile、SSLCertificateKeyFile,ServerName/ServerAlias 覆盖所有代理的域名,再执行 apachectl configtest。
防火墙: 安全组和系统防火墙放行 Cloudflare 公布的 IP 段访问 443,并把这些 IP 加进 fail2ban 等工具的白名单。
双向 TLS 源站: 要么在 Cloudflare 开启 Authenticated Origin Pulls,要么源站不再强制要求客户端证书。
源站前面还有一层负载均衡时
结构是“Cloudflare → 云厂商负载均衡 → 后端服务器”时,和 Cloudflare 握手的是负载均衡,而不是你登录的那台机器,所以要查负载均衡的配置:
- 负载均衡上要有 443 的 HTTPS 监听,并且绑定了覆盖所有域名的证书;只开了 80 的 HTTP 监听,就是第 1 种原因。
- 负载均衡的 TLS 安全策略决定了它接受哪些协议和套件。选了只含 TLS 1.2 加少数冷门套件的策略,可能和 Cloudflare 的清单没有交集,就是第 3 种原因。
- 后端服务器的 Nginx 配得再好也不影响这一段握手,改错了地方是排查时最常见的浪费时间。
直连测试时,-connect 后面填负载均衡的公网 IP,而不是后端机器的内网 IP。
协议和套件不确定怎么写,可以用 TLS 配置生成器 生成一份和 Cloudflare 清单有交集的配置。
怎么确认已经修好
直连源站的 openssl 握手成功,经 Cloudflare 访问不再返回 525,就说明修好了。
- 直连源站:
openssl s_client -connect 203.0.113.10:443 -servername example.com -brief能打印出协议版本、套件和证书主体。 - 通过 Cloudflare 访问:
curl -sI https://example.com/返回正常状态码,响应头里有cf-ray,不再是 525。 - 打算用 Full (strict) 的,同时检查源站证书链和域名,免得 525 修好又冒出 526。SSL 检测 可以看边缘证书情况;握手每一步可能在哪里失败,见 TLS 握手过程详解。
常见问题
把 Cloudflare 改成 Flexible 模式能解决 525 吗?
能让报错消失,因为 Flexible 模式下 Cloudflare 用明文 HTTP 回源,不做 TLS 握手。代价是 Cloudflare 到源站这段不加密,而且源站如果有 HTTP 跳 HTTPS 的规则,会立刻变成 ERR_TOO_MANY_REDIRECTS 重定向循环。只适合在给源站装证书之前临时顶一下。
525 和 526 有什么区别?
525 是握手本身没完成;526 是握手完成了,但在 Full (strict) 模式下 Cloudflare 认为源站证书无效,比如过期、自签名、域名不匹配或证书链不完整。
为什么 525 时有时无?
常见情况是同一个域名背后有多台源站,其中一台没配好;或者源站在高负载时重置握手;或者防火墙、fail2ban 之类的工具把 Cloudflare 的 IP 段限流或封禁了。Cloudflare 文档建议拿出现 525 的时间点去对源站的错误日志。
访客需要做什么吗?
不需要,也做不了什么。出问题的是 Cloudflare 到网站服务器那一段,清缓存、换浏览器、换网络都没用,只能由站长或主机商处理。