---
canonical: https://meta.cyberforums.com/t/cravatar-cf-525-403-301-404-200/1805
webpage: https://wpcy.com/community/t/1805-cravatar-cf-525-403-301-404-200
language: zh-Hans
---

# Cravatar 海外 CF 加速踩坑全记录 — 从 525 到 403 到 301 到 404 再到 200

> 文派叶子支持论坛的只读副本，本页不能回复。
> 讨论原文：https://meta.cyberforums.com/t/cravatar-cf-525-403-301-404-200/1805
> 网页版：https://wpcy.com/community/t/1805-cravatar-cf-525-403-301-404-200

## 1 · modiqi

- 发布时间：2026年2月25日 15:58

背景
cravatar.com 是头像服务，日调用 2000 万+。源站在南京（140.210.20.196），海外用户延迟高。目标：海外流量走 Cloudflare CDN 加速，国内流量不变。
听起来很简单对吧？阿里云 DNS 分流 + CF for SaaS，教科书级操作。然而这个「简单」的需求，让我连续踩了 6 个坑，迭代了 6 个版本的 Worker，才最终搞定。

第一回合：CF for SaaS + custom_origin_server（525）
标准方案：wpcy.net zone 添加 cravatar.com 为 custom hostname，custom_origin_server 设为 cravatar.wpcy.net（灰云 A 记录指向源站）。
结果：525 SSL handshake failed。
排查发现：CF 回源时 SNI=cravatar.wpcy.net，但源站拒绝这个 SNI。找 devops 改 nginx，加了 server_name cravatar.wpcy.net。
本地测试 nginx 正常，但外部访问还是被 reset。最终发现：不是 nginx 的问题，是机房网络层有 SNI 白名单过滤，只放行已备案域名。cravatar.wpcy.net 没备案，在网络层就被干掉了。
想用 custom_origin_sni 参数让 CF 回源时 SNI 用 cravatar.com？对不起，Enterprise 专属功能。

教训：国内机房的 SNI 过滤比你想象的更底层，nginx 配置正确也没用。


第二回合：CF Worker + HTTPS resolveOverride（还是 525）
既然 CF for SaaS 的 origin 配置搞不定 SNI，那用 Worker 自己控制回源。
思路：Worker fetch https://cravatar.com/path，URL hostname=cravatar.com 所以 SNI=cravatar.com（通过白名单），resolveOverride 指向灰云记录获取源站 IP（避免 DNS 回环）。
结果：还是 525。
原因：CF Worker 的 resolveOverride 改了 IP 解析，但 CF 内部 TLS 层的 SNI 用的是 resolveOverride 的 hostname（cravatar.wpcy.net），不是 URL hostname。
这个行为跟文档说的不一样（文档说 SNI 跟随 URL hostname），但实际测试就是这样。可能是 CF for SaaS 场景下的特殊行为。

教训：resolveOverride 的 SNI 行为在 CF for SaaS 场景下可能跟普通 zone 不同。


第三回合：Worker 直接 fetch IP（403）
既然域名都有问题，那直接用 IP 地址 fetch 行不行？
fetch('http://140.210.20.196/avatar/test', { headers: { Host: 'cravatar.com' } })

结果：403 Direct IP access not allowed。
CF 不允许 Worker fetch IP 地址。这是 CF 的安全策略，没有绕过方法。

教训：CF Worker 的 fetch 必须用域名，不能用 IP。


第四回合：Worker HTTP 回源 + cravatar.wpcy.net（404 / 机房拦截）
那用 HTTP 协议（80 端口）回源，绕过 TLS/SNI 问题。fetch http://cravatar.wpcy.net/path，Host header 设为 cravatar.com。
结果：404，响应体是机房拦截页面：「该网站暂时无法进行访问」。
原因：机房不仅过滤 TLS 的 SNI，HTTP 的 Host header 也检查。虽然我设了 Host: cravatar.com，但 HTTP 请求的目标域名是 cravatar.wpcy.net（从 URL 解析），机房在网络层看到的是 cravatar.wpcy.net，直接拦截。

教训：南京机房的域名过滤是全协议的，HTTP 和 HTTPS 都查。而且查的是 DNS 解析的目标域名，不是 Host header。


第五回合：Worker HTTP 回源 + cravatar.com hostname（301 回环）
那 fetch http://cravatar.com/path（Host=cravatar.com，通过机房检查），resolveOverride 指向灰云记录获取 IP。
结果：301 重定向到 https://cravatar.com/path。
原因：wpcy.net zone 开了 Always Use HTTPS，CF 对 Worker 的 subrequest 也应用这个设置。Worker fetch HTTP 请求 → CF 内部 301 → HTTPS → 又回到 Worker → 无限循环。

教训：CF 的 Always Use HTTPS 对 Worker subrequest 也生效，即使 subrequest 用了 resolveOverride。


第六回合：关闭 Always Use HTTPS + HTTP 回源（终于 200！）
关掉 wpcy.net zone 的 Always Use HTTPS，Worker fetch http://cravatar.com/path + resolveOverride。
结果：200！头像正确返回！
其他 custom hostname（wpcy.com、wpcommunity.com）的 HTTPS 重定向由源站自行处理（WordPress 和 Discourse 都有自己的 HTTPS 强制），不依赖 CF 的 zone 级别设置。

最终架构
海外用户 → HTTPS → CF Anycast → Worker 拦截
  → HTTP fetch cravatar.com（resolveOverride → 灰云记录 → 源站 IP）
  → 源站 80 端口（Host=cravatar.com，通过机房备案检查）
  → 响应回传 → CF 边缘缓存（/avatar/* 30天）→ 用户

国内用户 → HTTPS → 阿里云 DNS 境内线路 → 源站 443 端口（直连）

Worker 代码只有 55 行，但为了写出这 55 行，我迭代了 6 个版本。
关键经验总结

国内机房（至少南京这家）同时检查 TLS SNI 和 HTTP Host/目标域名，只放行已备案域名
CF for SaaS 的 custom_origin_sni 是 Enterprise 专属
CF Worker resolveOverride 在 SaaS 场景下 SNI 行为可能异常
CF Worker 不能 fetch IP 地址
CF Always Use HTTPS 对 Worker subrequest 也生效
最终方案：HTTP 回源 + resolveOverride + 关闭 zone 级 HTTPS 强制

每一个坑都不是文档里能找到的，全靠实测。希望后来人少走弯路。

## 2 · modiqi

- 发布时间：2026年2月25日 19:53

第七个坑：源站 HTTP→HTTPS 308 重定向导致循环
上线后用户反馈开 VPN 访问 cravatar.com 首页出现 ERR_TOO_MANY_REDIRECTS。
原因：Worker 对所有路径统一 HTTP 回源，但源站对非 /avatar/ 路径的 HTTP 请求返回 308 重定向到 HTTPS。浏览器跟随 308 → 再次进入 CF → Worker 又用 HTTP 回源 → 源站又 308 → 无限循环。
/avatar/* 路径不受影响，因为源站对这个路径直接返回 200（不重定向）。
临时修复：Worker 检测到源站返回同域名 HTTPS 重定向时，返回降级提示页面（不再循环）。API 路径正常工作。
根治方案：已联系 devops 在源站 nginx 加条件判断 — 对带 X-CF-Worker header 的 HTTP 请求跳过 HTTPS 重定向。Worker 已在所有回源请求中加了这个 header。
又一个教训：源站的 HTTPS 强制重定向 + Worker HTTP 回源 = 重定向循环。这在测试 /avatar/ 路径时发现不了（因为 avatar API 不重定向），只有用户访问首页时才暴露。

## 3 · modiqi

- 发布时间：2026年2月25日 19:58

已完全修复
devops 在源站 nginx 加了条件判断：带 X-CF-Worker header 的 HTTP 请求跳过 HTTPS 重定向。
现在所有路径都正常：

首页 200 （HTML，text/html）
/avatar/* 200 （图片，30 天缓存）
/favicon/* 200 
国内直连不受影响 

最终 Worker 代码精简到 45 行，正式上线。
完整踩坑清单（7 个）：

CF for SaaS custom_origin_server → 机房 SNI 白名单拦截（525）
custom_origin_sni → Enterprise 专属
Worker HTTPS + resolveOverride → SNI 跟随 override hostname（525）
Worker fetch IP → CF 禁止（403）
Worker HTTP + 非备案域名 hostname → 机房 Host 检查拦截（404）
Worker HTTP + 备案域名 → Always Use HTTPS 拦截（301 循环）
源站 HTTP→HTTPS 308 重定向 → Worker HTTP 回源循环（ERR_TOO_MANY_REDIRECTS）

每一个都是实测才发现的，文档里找不到。

## 4 · modiqi

- 发布时间：2026年2月25日 21:50

第八个坑：Page Rule 301 重定向丢失路径
cravatar.cn 迁入 CF 时设的 Page Rule 把 cravatar.cn/* 重定向到 https://cn.cravatar.com（固定 URL），没有用 $1 保留路径。导致 cravatar.cn/avatar/xxx 被重定向到 cn.cravatar.com（首页），头像全挂。
修复：改为 https://cn.cravatar.com/$1。
教训：CF Page Rule 的 forwarding URL 如果不带 $1，路径会被丢弃。这是个低级错误但影响很大 — 所有通过 cravatar.cn 调用的头像 API 全部失效。

## 5 · modiqi

- 发布时间：2026年2月26日 13:24

补充：源站缺少 Cache-Control 响应头（已修复）
排查 cravatar.cn zone 的 0% 缓存命中率时，发现一个更根本的问题：源站 avatar.php 在成功返回头像时没有设置 Cache-Control 头。
问题
curl -I https://cn.cravatar.com/avatar/test 响应头里没有 Cache-Control。只有错误响应（c_die 函数）设了 Cache-Control: no-cache，正常头像响应完全没有缓存指示。
这意味着：

浏览器每次都会重新请求头像（无本地缓存）
CF Worker 边缘缓存没有明确的 TTL 指引
中间 CDN（cn.cravatar.com 前面的那层）也缺少缓存依据

修复
在 /www/wwwroot/cravatar/wp-content/plugins/cravatar/pages/avatar.php 第 464 行（紧跟 Avatar-From header 之后）加了一行：
header( 'Cache-Control: public, max-age=2592000' );

30 天缓存，与 nginx 静态文件的 expires 30d 保持一致。
验证
$ curl -sI https://cn.cravatar.com/avatar/test123 | grep cache-control
cache-control: public, max-age=2592000

$ curl -sI https://cravatar.com/avatar/test123 | grep cache-control
cache-control: public, max-age=2592000

两个域名都已生效。
备注
cravatar.cn zone 的 0% 缓存命中率是正常的 — 该 zone 只做 301 跳转到 cn.cravatar.com，Cloudflare 不缓存 301 响应。真正的头像内容由 cn.cravatar.com 提供（不走 Cloudflare，走另一套 CDN）。
