搞定 Cloudflare Pages 优选 IP:从 522 报错到秒开的“偷梁换柱”避坑指南

折腾背景:

最近想给部署在 Cloudflare Pages 上的静态博客(aaaa.com)搞个国内优选 IP 加速。毕竟 Cloudflare 自带的线路在国内“众生平等”地慢,要想速度快,必须得上 Cloudflare for SaaS (Custom Hostnames) 大法。

本以为是个常规操作:开通 SaaS -> 设好 CNAME -> 解析到优选 IP,完事。
结果现实直接给我上了一课:Error 522 Connection Timed Out

折腾了一下午,终于搞明白了其中的逻辑闭环。这不仅仅是配个 DNS 那么简单,这里面藏着一个关于“身份认证”的深坑。为了方便后来人避坑,我把整套逻辑复盘一下。


一、 为什么会翻车?(Error 522 的真相)

为什么会翻车

我的架构初衷很简单:

  1. 用户 访问 aaaa.com
  2. DNS 指向我的 SaaS 加速域名 cdn.tb.bbbb.com(背后是优选 IP)。
  3. Cloudflare 回源到我的 Pages 源站 my-blog.pages.dev

看起来很完美对吧?但当我访问时,直接报错 522。

根本原因:Pages 的“洁癖”

Cloudflare Pages(还有 Vercel、Netlify 这类平台)是共享环境。为了安全,它们只认**“绑定过的域名”**。

当流量通过 SaaS 回源过来时,请求头里的 Host 依然是我的主域名 aaaa.com
数据包到达 Pages 服务器时,发生了如下对话:

Cloudflare SaaS: “兄弟,给我取一下 aaaa.com 的数据。”
Pages 服务器: “谁?aaaa.com?我不认识。我的系统里只绑定了 my-blog.pages.dev。这连接我不接,挂了。”

于是,我的浏览器直接弹出了 522 Connection Timed Out(连接超时)。

我当时第一反应是:“那我去 Pages 后台绑定一下 aaaa.com 不就行了?”
千万别! 这样做会导致 Cloudflare 内部的控制权冲突(Metadata Conflict),SaaS 优选会直接失效。


二、 破局思路:给请求头“整容”

既然问题的根源是 “名字对不上”(Host 头是 aaaa.com,而 Pages 只认 pages.dev),那解决思路就很简单了:

我们需要在请求到达 Pages 服务器之前,把请求头里的 Host 偷偷改掉。

在 Cloudflare 的生态里,能完美胜任这个“中间人截胡”工作的,就是 Cloudflare Worker

为了更直观地理解这个逻辑,我们把这个流程想象成一次 “酒店入住”

  • 大酒店:Cloudflare 全球网络。
  • 住客:我的域名 aaaa.com
  • 前台接待:我的 SaaS 主账号 bbbb.com
  • VIP 房间:我的源站内容 my-blog.pages.dev

1. 失败的自助入住(直连)

住客 aaaa.com 拿着优选 IP 的门票进了酒店。前台查了查名单(Custom Hostnames),确认是会员,于是指引他去 VIP 房间。
住客走到门口敲门:“我是 aaaa.com,让我进去。”
房间里的人一看:“名单上只写了 my-blog.pages.dev 能进,你谁啊?不开门。”
卒。

2. 成功的管家服务(Worker 介入)

我们在通往房间的走廊里,安排了一个 “私人管家” (Worker)
流程变成了这样:

  1. 住客 aaaa.com 进门。
  2. 管家截胡:在住客敲门之前,管家把他拦住了。
  3. 偷梁换柱:管家说:“老板,这样进去会被赶出来的。”于是,管家给住客换了一身衣服,贴上了 my-blog.pages.dev 的名牌。
  4. 顺利入住:管家带着换好装的请求去敲门。房间里的人一看:“哦,是 my-blog.pages.dev 啊,自己人,请进!”

这就是 Worker 的核心作用:重写 Host Header

Saas处理逻辑

三、 抄作业:最终解决方案

Woker请求重写流水线

第一步:SaaS 端的准备 (bbbb.com)

在我的 SaaS 主账号(提供优选接入的那个账号)里:

  1. Custom Hostnames:添加 aaaa.com 并完成 TXT 验证(这一步是必须的,相当于办理入住登记,否则进不了大门)。
  2. Fallback Origin:填写回源跳板域名,比如 origin.cdn.tb.bbbb.com
  • 注:这里的 Fallback 只是为了满足 SaaS 配置的必填要求。实际流量会被 Worker 拦截,所以不需要它真的能访问什么。
  1. DNS 设置 (关键)
  • origin.cdn.tb 解析到 192.0.2.1(一个假 IP)。
  • 必须开启小黄云 (Proxied)!否则 Worker 无法拦截请求。

第二步:部署“管家”代码 (Worker)

创建一个 Worker,把下面的代码贴进去。
这段代码不仅解决了 522 问题,还加了 SEO 防权重分散强制 HTTPS 以及 请求上下文透传(保留 Cloudflare 的 Bot 识别、地理位置等信息)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
export default {
async fetch(request, env, ctx) {
const url = new URL(request.url);

// === 你的配置 (请务必修改这里) ===
const PRIMARY_DOMAIN = 'aaaa.com'; // 你的对外主域名
// ⚠️ 注意:这里必须填你 Pages 项目的完整域名,不能漏掉子域名!
const TARGET_ORIGIN = 'my-blog-project.pages.dev'; // 你的 Pages 源站完整地址

// === 逻辑 1: 门卫拦截 (SEO 优化) ===
// 防止别人直接访问 worker 地址或跳板域名,非主域名一律跳回主页
if (url.hostname !== PRIMARY_DOMAIN) {
const targetUrl = `https://${PRIMARY_DOMAIN}${url.pathname}${url.search}`;
return Response.redirect(targetUrl, 301);
}

// === 逻辑 2: 安全检查 (强制 HTTPS) ===
if (url.protocol === 'http:') {
url.protocol = 'https:';
return Response.redirect(url.toString(), 301);
}

// === 逻辑 3: 偷梁换柱 (核心回源逻辑) ===

// 1. 修改 URL 对象指向 Pages 源站
// 这一步是为了确保 fetch 能够寻址到正确的 Pages 服务器 IP
const targetUrl = new URL(request.url);
targetUrl.hostname = TARGET_ORIGIN;
targetUrl.protocol = 'https:';

// 2. 复制并修改请求头
// 关键点:把 Host 头改成 Pages 认识的域名,欺骗 Pages 服务器
const newHeaders = new Headers(request.headers);
newHeaders.set('Host', TARGET_ORIGIN);

// 3. 构建新请求
// 关键点:透传 request.cf 对象,保留 GeoIP、Bot Score 等边缘信息
const newRequest = new Request(targetUrl, {
method: request.method,
headers: newHeaders,
body: request.body,
redirect: 'manual',
cf: request.cf
});

try {
return await fetch(newRequest);
} catch (e) {
// 如果出现 525 错误,请检查 SaaS 账号的 SSL 设置
return new Response(`Worker Error: ${e.message}`, { status: 500 });
}
},
};

第三步:绑定路由(🔥 最容易翻车的地方!)

代码写好了,管家得知道该拦谁。我最开始就是在这里栽了跟头,把路由绑定到了跳板域名上,结果访问主域名根本不触发 Worker。

  • 回到 Worker 的 Settings -> Triggers
  • Add route:
  • Route: aaaa.com/* (注意:这里要填你的用户实际访问域名)
  • Zone: bbbb.com (必须选 SaaS 主账号所在的区域,千万别选 aaaa.com 的区域!)

四、 避坑 CheckList

鼓掌排查决策树

如果你配置完还是 522 或 525,请灵魂三问:

  1. SSL 模式对吗?
    SaaS 主账号 (bbbb.com) 的 SSL/TLS 建议优先开到 Full (Strict)
  • 如果遇到 525 握手失败,可以尝试降级为 Full
  1. 路由 Trigger 对吗?
    再检查一遍 Worker 的 Route。浏览器里输入什么域名,Route 就要匹配什么域名。不要去匹配那个 192.0.2.1 的跳板域名。
  2. TARGET_ORIGIN 填完整了吗?
    代码里的 TARGET_ORIGIN 必须是 project-name.pages.dev 这种完整格式,不能只填 pages.dev

总结

Cloudflare for SaaS + Pages 是个好东西,能免费享受 Pages 的 CI/CD 和优选 IP 的速度。虽然配置过程有点绕,但只要理解了 “SaaS 负责进门,Worker 负责改名,Pages 负责出货” 这套逻辑,其实也非常清晰。

希望这篇复盘能帮你省下一下午的调试时间。Enjoy your fast website! 🚀