Cloudflare 橙云灰云搞反,站点立刻挂 —— 排查与修复

Cloudflare DNS 那个橙云图标决定流量走 CDN 边缘还是直连源站。切错状态会以微妙的方式弄断 SSL、WebSocket、apex CNAME。

Cloudflare 的 DNS 面板里每条 A / AAAA / CNAME 旁边都有个小橙云图标。橙色 = 走 Cloudflare 边缘代理;灰色 = 纯 DNS、流量直连源站。很多人没意识到这个图标改了多少东西——它不只是 CDN 开关。橙云会重写 SSL 链、把源站 IP 藏起来、把每个请求过一遍 WAF、DNS 返回的是 Cloudflare 的 IP。从橙切灰、或者灰切橙,是所有 Cloudflare 前置场景下”我什么都没改它就坏了”排名第一的原因。症状从 SSL 警告突然冒出来、到 WebSocket 不停断、到 SSL 签发商拒绝发证、到第二天源站被直接打爆,应有尽有。

常见原因

每条都是”云切错”——分清楚你在哪种场景,就知道往哪边切。

1. 源站签 SSL 时需要灰云

Let’s Encrypt 的 HTTP-01 challenge 打 http://yourdomain.com/.well-known/acme-challenge/...。橙云的话 Cloudflare 边缘先应答——它送自己的响应、不是源站的 challenge 文件。CA 验不过,签发就挂在 pending。

怎么判断:平台(Vercel / Render / Fly / 自建)SSL 状态卡 pending 几小时。Cloudflare DNS 里 apex 或 www 的 A 记录是橙云。

2. WebSocket 被边缘截断

Cloudflare 免费版和 Pro 通过橙云代理支持 WebSocket,但有 100 秒 idle 超时、大部分套餐只走 HTTP。长连接应用(Phoenix Channel / Socket.IO / 实时协作),橙云上每 100 秒就掉一次。

怎么判断:连接每 100 秒左右重连一次,错误码 1006going away。直连源站能挂几小时不动。

3. apex CNAME flattening 把流量带进 Cloudflare 边缘了

你把 yourdomain.com 设成 app.platform.com 的 CNAME。DNS 原生不允许 apex CNAME,所以 Cloudflare “flatten” 它——但只有橙云才 flatten。灰云时 CNAME 原样返回,很多解析器对 apex 查询会拒绝。

怎么判断:灰云 + apex CNAME = apex 间歇性 NXDOMAIN。橙云能用,但返回的是 Cloudflare IP,不是平台 IP。

4. 源站只靠 Cloudflare 隐藏 IP 才安全

你几周前开了橙云。后来因为某事切到了灰云(签证书、调试、厂商指引)。DNS 现在直接返回源站 IP,之前找不到源站的攻击者立刻能直打了。

怎么判断:源站负载飙升,日志里直接来源命中、不是 Cloudflare IP 段(缺少 cf-connecting-ip header)。

5. SSL Full vs Flexible 不匹配在切换时暴露

橙云的时候,Cloudflare 的 SSL 模式(Flexible / Full / Full-Strict)决定它怎么跟源站说话。源站把 HTTP 跳到 HTTPS、Cloudflare 是 Flexible 模式,就死循环重定向。源站是自签名、Cloudflare 是 Full-Strict,就报 526。

怎么判断ERR_TOO_MANY_REDIRECTS(Flexible + 源站跳 HTTPS)、526 Invalid SSL certificate(Full-Strict + 源站自签名)。

6. Page Rules / Workers 只在橙云时跑

Page Rules、Workers、Transform Rules、Cache Rules——灰云记录这些都不跑。你为”DNS 调试”切了灰云就忘了,边缘逻辑就静默失效。

怎么判断:Worker 注入的 header 没了。Cloudflare 缓存命中率掉到 0。浏览器 DevTools 里没有 cf-ray header。

开始前

  • 打开 Cloudflare DNS 面板,记下每条记录(apex、www、相关子域)当前的云颜色。
  • 看 Cloudflare 仪表盘里的 SSL/TLS 模式:Flexible / Full / Full-Strict / Strict-Origin。
  • 看清楚每个子域是哪个平台在跑(源站、Vercel、Fly…)——不同平台需要不同的云状态。
  • 手边留着源站直连 IP,必要时用 curl --resolve 测试。

需要收集的信息

  • dig yourdomain.com +short 输出——Cloudflare IP(一般 104.x 或 172.67.x)还是源站 IP。
  • curl -I https://yourdomain.com 输出——看 cf-ray:server: cloudflare
  • Cloudflare SSL/TLS 标签页的 SSL 模式设置。
  • DNS 记录列表带云图标的截图。
  • 最近变更日志:谁切的、什么时候、为什么。

一步步修

按你的场景选模式。

第 1 步:每条记录想清楚目标状态

简单规则:

  • apex A 指向平台 IP(Vercel / Netlify):发完证书可以开橙云,但平台可能不支持被 Cloudflare 代理。看平台文档。Vercel 和 Netlify 一般偏好灰云。
  • apex 是 CNAME 指向 <platform>.com:橙云能 flatten,但源站平台可能拒绝 Host header 里的 Cloudflare IP。按平台具体文档测。
  • 自建源站(自己的 VM / 容器):橙云推荐,吃 DDoS 防护 + 缓存。SSL 模式 Full-Strict,配真证书。
  • 邮件记录(MX / SPF / DKIM):永远不代理。邮件服务器不说 HTTP。永远灰云。(Cloudflare 本来也不让你橙云化 MX。)
  • WebSocket 重的子域:免费版 / Pro 需要超过 100 秒就灰云,或者升级套餐。

第 2 步:签 SSL 期间切灰云

1. Cloudflare DNS 面板
2. 点 apex(或 www)记录旁边的橙云
3. 变灰
4. 等 30 秒左右让 Cloudflare 边缘的 DNS 传播
5. 在平台重新触发 SSL 签发
6. 等 "issued"
7. 灰云切回橙云(如果你需要 Cloudflare 在前面)

签发完可以再开橙云。平台的证书还在源站;Cloudflare 在外面再加一层边缘证书。

第 3 步:把 Cloudflare 到源站的 SSL 模式调对

Cloudflare 仪表盘 → SSL/TLS → Overview:

源站状态必须的 Cloudflare 模式
源站有 Let’s Encrypt / 公共 CA 证书Full (strict)
源站只有自签名Full
源站只听 HTTP :80Flexible(生产别用)
源站装了 Cloudflare Origin CertFull (strict)

Flexible 让 Cloudflare 到源站走明文 HTTP,向用户报告 HTTPS——看着安全但其实不是,源站也跳 HTTPS 的话直接死循环。

第 4 步:WebSocket 需求长连接的话,选灰云或升级套餐

要长连接:

  • 方案 A:把 WebSocket 流量挪到专门子域(ws.yourdomain.com),那条记录灰云。apex HTTP 流量留橙云。
  • 方案 B:升级 Cloudflare Business 或 Enterprise,去掉 100 秒上限。
  • 方案 C:用 Cloudflare Spectrum(Enterprise),不带 WebSocket HTTP 封套的全 TCP 代理。

第 5 步:临时切灰云调试一定要设日历提醒

常见坑:调试切了灰云,忘了,过几周。来一条:

echo "CHECK CLOUDFLARE: 是不是把 apex 切回橙云了?" | at now + 2 hours

或者 Slack / Linear 任务。忘记橙云 = 失去 WAF、DDoS 防护、Workers、缓存。

第 6 步:灰云的话审计源站 IP 暴露

如果你确实要灰云:

dig yourdomain.com +short
# 直接返回源站 IP — 谁都能拿到

缓解:

  • 把源站防火墙配成只接受 Cloudflare IP 段(https://www.cloudflare.com/ips-v4/)——前提是你打算切回橙云。
  • 永久灰云的话,把源站当成完全暴露处理:真正的防火墙、fail2ban、常规 DDoS 准备。

验证

  • curl -I https://yourdomain.com 在橙云时有 cf-ray: header、灰云时没有。
  • dig yourdomain.com +short 在橙云时返回 Cloudflare IP 段(104.x / 172.67.x),灰云时返回源站 IP。
  • 浏览器 DevTools 里 SSL 证书链:橙云签给你的域名、issuer 类似 “Cloudflare Inc ECC CA-3”;灰云直接是 Let’s Encrypt 或源站 CA 签的。
  • 需要长连接时,超过 100 秒 WebSocket 不掉(灰云或升级了套餐)。
  • 仪表盘里橙云记录的 Workers / Page Rules / Cache Rules 看到非零流量。

长期预防

  • 把云图标当作生产开关,需要同伴 review,不要随手切。
  • DNS-as-code 仓库里写清楚每条记录的目标状态(Terraform cloudflare_record proxied = true/false)——PR diff 能挡住误切。
  • 用 Cloudflare 审计日志对任何 DNS 变更告警,每周 review。
  • 每次临时切灰云都立刻挂一个”切回来”的任务、带 deadline。
  • 标准化 SSL 模式为 Full (strict),所有源站发 Cloudflare Origin Cert——彻底消除 Flexible / Full 的模糊地带。

常见坑

  • 为签证书切灰、忘了切回橙——静默失去 CDN、WAF、源站隐藏。
  • SSL 模式调 Flexible,因为”浏览器里看着行”——CF 到源站走明文 HTTP,任何 auth header 都暴露。
  • 试图把 MX 记录橙云化(Cloudflare 直接拒绝),结果被错误信息搞糊涂。
  • apex CNAME 配灰云,间歇命中那些不支持 apex CNAME 的解析器就挂——要 flatten 必须橙云。
  • 忘了橙云时 Cloudflare 在边缘终结 TLS、源站证书不匹配对浏览器不可见、但会弄坏 Full-Strict 模式。

FAQ

Q:为什么浏览器看到的 Let’s Encrypt 证书 issuer 是 “Cloudflare Origin CA”?

不是的——浏览器看到的是 Cloudflare 的边缘证书,Cloudflare 给你的域名签的。源站的 Let’s Encrypt 证书存在于 Cloudflare 跟源站之间(或者不存在,Flexible 模式)。橙云下浏览器永远看不到源站证书。

Q:apex 橙、www 灰可以吗?反过来呢?

可以。每条记录都有自己的云状态。注意两边互相重定向(root ↔ www)时,要清楚是哪边在 Cloudflare 前面。

Q:WebSocket 在橙云下挺正常,100 秒上限消失了?

可能是连接自动重连了(Socket.IO 自带),或者升级了套餐,或者你的 socket 本来就短。上限是针对一条无数据的 idle TCP 连接、不是逻辑会话。

Q:报 526 是什么?

Cloudflare 到源站的 SSL 握手在 Full (strict) 模式下失败。源站证书过期了、自签名、或者主机名不对。修源站证书,或者 SSL 模式降到 Full(不 strict,接受自签名)。

延伸阅读:绑了自定义域名但 SSL 没发SSL 混合内容警告HTTPS 没强制A 记录跟 CNAME 分不清

标签: #排查 #cloudflare #DNS #proxy #排查