11 KiB
TamaBox 双 CDN 接入指南:境内腾讯 EdgeOne + 境外 Cloudflare
目标:中国大陆访客走腾讯 EdgeOne 节点加速,境外访客走 Cloudflare 边缘网络加速,共用同一域名与源站。 代码前置:
internal/shared/ip.go自 2026-09-03 起在trust_proxy = true时信任 EdgeOne 权威客户端头EO-Client-IP(等效CF-Connecting-IP)。单 EdgeOne 或双 CDN 部署均可直接用本文件配套。
0. 总体架构
┌──────────────── DNS(DNSPod 智能解析)─────────────────┐
│ 线路「境内」 → CNAME → EdgeOne 分配的 CNAME │
│ 线路「境外」 → CNAME → Cloudflare for SaaS CNAME │
│ 线路「默认」 → CNAME → Cloudflare(未匹配线路兜底) │
└───────────────┬───────────────────┬────────────────────┘
▼ ▼
EdgeOne(腾讯,大陆节点) Cloudflare(全球边缘)
│ │
└─────► 源站(仅放行两家回源网段)◄──────┘
TamaBox (Flamego) + PG + Redis
核心思路:CDN 各自接入,DNS 按线路分发。两家 CDN 都不需要托管你的主域名 NS,主域名 NS 全程留在 DNSPod(腾讯云解析),靠「境内 / 境外 / 默认」三条线路把用户分给不同的 CNAME 目标。
1. 前置条件(逐项确认)
| # | 条件 | 说明 |
|---|---|---|
| 1 | 域名已 ICP 备案 | EdgeOne 加速区域含「中国大陆 / 全球可用区」时的硬性要求,不可绕开 |
| 2 | 腾讯云账号已实名 | 开通 EdgeOne 需要 |
| 3 | Cloudflare 账号 | Free 套餐即可(见步骤 3 的 SaaS 说明) |
| 4 | 一个闲置域名(或其子域)用于 Cloudflare 承载 zone | Cloudflare for SaaS 需要一个已托管在 CF(NS 迁过去)的域名作为“承载 zone”,主域名不需要迁 NS。没有就考虑末尾的备选方案 C |
| 5 | 源站公网可达 | 回源协议 / 端口按你的部署调整 |
2. 步骤 1:DNS 迁到 DNSPod 并建立分线路骨架
- 在 DNSPod(腾讯云解析)添加你的域名,按提示把注册商处的 NS 改成 DNSPod 提供的
xxx.dnspod.net两条。 - 等解析生效后,先建立保底记录,避免切换期中断:
- 线路「默认」:
www→ CNAME → EdgeOne(或先保持源站 A 记录,逐步切); - 建议把各记录 TTL 临时调小(如 60 秒),切换完成后再调回。
- 线路「默认」:
- ⚠️ 若根域(
@)承载邮箱(存在 MX 记录),不能给@配 CNAME(与 MX 冲突)。此时只对www/ 业务子域做 CDN 加速,@保持 A 记录直连或做 301 跳转。
3. 步骤 2:EdgeOne 接入(CNAME 模式)
- 控制台 → 添加站点 → 输入主域名 → 选购套餐 → 加速区域:中国大陆可用区(境外交给 Cloudflare)。
- 接入模式选 CNAME 接入(主域名 NS 在 DNSPod,不能用 NS 接入)。
- 归属权验证:按控制台提示在 DNSPod 添加 TXT 或做文件验证。
- 添加加速域名:在「域名服务 → 域名管理 → 添加域名」里填业务主机名(
www或@)+ 源站 IP/域名。 - 平台分配一个 CNAME 地址(形如
xxx.edgeone.net),先记下来,步骤 5 统一填到 DNSPod。 - 证书:开启「站点加速 → HTTPS」自动证书(免费)。
4. 步骤 3:Cloudflare for SaaS(主域名不迁 NS 的关键)
Cloudflare Free/Pro/Business 套餐的普通接入要求把整个 zone 迁到 CF 的 NS,与分线路解析冲突。Cloudflare for SaaS(Free 套餐含 100 个自定义主机名免费)允许主域名不迁 NS、仅用 CNAME 挂到 CF:
- 用闲置域名(如
cf-host.example)在 Cloudflare 添加 zone,并把该域名的 NS 迁到 Cloudflare(承载 zone,仅此域名迁)。 - 承载 zone 内:
SSL/TLS → Custom Hostnames(SSL for SaaS)→ Add Custom Hostname,填入你的主域名(如www.example.com)。 - 按提示完成归属验证:CF 会给出一条验证 TXT(加到 DNSPod)+ 一个 CNAME 目标值(形如
xxx.1234.cdn.cloudflare.net),记下来用于步骤 5 的境外线路。 - 等待证书签发至状态
Active(通常数分钟到数小时)。之后 CF 自动管理该域名的证书与续期。
备选:若不想多养一个域名做承载 zone,可退回方案 C——EdgeOne 加速区域直接选「全球可用区」,一家覆盖全球,不做 Cloudflare(代价:境外节点质量与覆盖面不如 CF)。或评估 Cloudflare Business(约 $200/月)的官方 CNAME 接入。
5. 步骤 4:DNSPod 分线路记录(最终形态)
同一主机名、不同线路分别建行(全部 CNAME,避免 A/CNAME 冲突提示):
| 主机记录 | 线路 | 类型 | 记录值 | 说明 |
|---|---|---|---|---|
www |
境内 | CNAME | xxx.edgeone.net(EO 分配) |
大陆走 EdgeOne |
www |
境外 | CNAME | xxx.…cdn.cloudflare.net(SaaS 分配) |
境外走 Cloudflare |
www |
默认 | CNAME | xxx.…cdn.cloudflare.net |
未匹配线路(如部分境外 DNS)兜底 |
验证:境内
dig www.example.com(或nslookup)应解析出 EdgeOne CNAME;用境外 DNS(如dig @8.8.8.8)应解析出 Cloudflare CNAME。不同递归节点可能有缓存,等待 TTL 过期后复测。
6. 步骤 5:源站锁定(安全前提,不可跳过)
trust_proxy = true 意味着应用信任 CDN 写来的客户端头,前提是请求只能来自这两家 CDN:
- 从官方渠道取回源网段并配置防火墙 / 安全组,仅放行:
- Cloudflare 官方 IP 段:https://www.cloudflare.com/ips/ (
cloudflare.com/ips-v4、ips-v6) - EdgeOne 回源 IP 段:腾讯云 EdgeOne 文档「回源 IP 网段」页(会动态更新,建议做成定期同步或至少配置时核对)
- Cloudflare 官方 IP 段:https://www.cloudflare.com/ips/ (
- 放行你的运维入口(SSH 管理 IP)与回源端口(80/443),其余一律拒绝直连。
- 回归验证:跑一次仓库自带的
dev/security-selfcheck.sh,确认带伪造CF-Connecting-IP的直连请求已被防火墙拦下(应无法到达应用)。
7. 步骤 6:真实 IP 传递(EdgeOne 侧关键配置!)
EdgeOne 默认不携带 EO-Client-IP,必须在控制台开启,否则经 EdgeOne 的请求到源站后拿不到客户端真实 IP(自动封禁会误伤所有大陆访客):
- 站点级:
站点加速(全局)→ 网络优化 → 客户端 IP 头部配置 → 开启,头部名称务必填EO-Client-IP(代码固定读这个名字,大小写敏感)。 - 或域名级:
规则引擎 → 创建规则(Host 匹配该域名)→ 操作:客户端 IP 头部 → 开启 → 名称填EO-Client-IP``。
Cloudflare 侧无需额外配置:CF-Connecting-IP 默认就有且恒被 CF 覆盖为真实客户端 IP。
8. 步骤 7:防“借道伪造”剥离规则(双 CDN 特有安全约束)
两家并存时出现新的伪造面:攻击者借道 CDN-A 时携带 CDN-B 的权威头。例如客户端经 Cloudflare 访问时自行塞一个 EO-Client-IP: 任意IP,若 CF 透传该头到源站,代码会信任它 → 可绕过限流 / 自动封禁 / 单 IP 投票限制,或嫁祸他人。因此必须在两家 CDN 的回源请求上剥离对方权威头:
| CDN | 剥离动作 | 位置 |
|---|---|---|
| Cloudflare | 回源前删除请求头 EO-Client-IP |
Rules → Transform Rules → Modify Request Header(Free 套餐可用,规则数有限但只建一条即可) |
| EdgeOne | 回源前删除请求头 CF-Connecting-IP |
规则引擎 → 操作:修改回源请求头 → 删除 CF-Connecting-IP(或站点全局回源请求头设置) |
X-Forwarded-For/X-Real-IP不需要在此剥离:代码只在 TCP 对端落入trusted_proxies时才解析它们,两家 CDN 边缘 IP 不在清单内,天然不可信。验证方法:分别经两家 CDN 发起带伪造头的请求(如
curl -H 'EO-Client-IP: 203.0.113.66' https://www.example.com/),在源站访问日志里确认最终到达的请求不包含伪造的对方头,且应用记录的客户端 IP 为你的真实出口 IP。
9. 步骤 8:应用配置(conf/app.ini)
[security]
trust_proxy = true
; trusted_proxies 仅用于“你自己的”反代/LB(如本机 nginx 127.0.0.1),
; 双 CDN 场景不需要也不应把两家 CDN 的全量网段填进来(代码直接信任 CF-Connecting-IP / EO-Client-IP)。
trusted_proxies =
[server]
; 若用防火墙按网段放行回源,可继续监听 :443;若希望更严,可只监听本机 + 本机回源代理。
listen =
行为(2026-09-03 起):trust_proxy = true 时 ResolveClientIP 依次信任 CF-Connecting-IP → EO-Client-IP → (仅当 TCP 对端在 trusted_proxies 内)解析 XFF/X-Real-IP → 最后回退 RemoteAddr。
10. 步骤 9:缓存与动态内容
TamaBox 是动态应用:
- 两侧都不要缓存 HTML / 页面 / API 响应;只缓存静态资源。
- EdgeOne:缓存规则命中
/static/*与带版本号资源即可; - Cloudflare:
Caching → Cache Rules对/static/*开缓存,其余Bypass。
- EdgeOne:缓存规则命中
- 若将来启用 WebSocket 长连接:Cloudflare Free 支持;EdgeOne 需在站点配置里显式开启 WebSocket。
- 注意两侧的 TLS 版本 / HTTP/3 行为差异属正常现象,与应用无关。
11. 上线切换与回滚
- 先切「默认」线路 → 观察 15~30 分钟(错误率、日志中的真实 IP 是否正确)。
- 再切「境内」线路(EdgeOne CNAME 生效)→ 用大陆网络(或大陆 DNS 递归查询)验证。
- 最后切「境外」线路到 Cloudflare SaaS CNAME → 境外访问验证 + 证书状态
Active。 - 回滚:把对应线路的 CNAME 改回原记录即可,秒级生效(DNS TTL 决定传播速度)。
12. 故障排查速查
| 现象 | 检查 |
|---|---|
| 大陆访问慢 / 未走 EO | DNSPod「境内」线路是否已配 EO CNAME;nslookup 从大陆递归查询结果 |
| 境外访问失败 / 证书错误 | SaaS Custom Hostname 状态是否 Active;境外线路 CNAME 是否拼错 |
| 自动封禁误封 / 限流全走同一个 IP | EO「客户端 IP 头部」是否开启且名称是否为 EO-Client-IP;trust_proxy 是否 true |
| 应用日志里出现伪造 IP | 两家剥离规则是否生效;防火墙是否真的挡住了直连 |
| 根域无法配 CNAME | 根域有 MX → 只加速 www/业务子域,@ 保持 A 记录 |
13. 相关代码与文档
- 代码改动:
internal/shared/ip.go(EO-Client-IP信任分支)、internal/shared/ip_test.go(新增 4 条用例)、internal/conf/static.go与conf/app.sample.ini(注释同步)。 - 单 CDN Cloudflare 加固参考:
outputs/cloudflare-origin-lockdown-guide.md。 - EdgeOne 客户端 IP 头部(腾讯官方文档,会更新):「携带客户端 IP 头部回源」。
- Cloudflare for SaaS 官方文档:developers.cloudflare.com → SSL/TLS → SSL for SaaS。