splitdns 使用教程:把一个子域名配成「海外走 CF、国内走别的 CDN」

这是 splitdns 的使用教程。原理和纯手动的做法见另一帖:主域名留在 Cloudflare,只把一个子域名委派给 DNSPod 做国内外分流

工具是 Windows / macOS 桌面版,开源(MIT):github.com/woodchen-ink/splitdns,下载见 Releases


它在解决什么

Cloudflare 的权威 DNS 不支持普通记录按地区返回不同答案;而记录一旦是橙云,返回的又是全球一致的 anycast IP。所以「同一个域名,不同地区解析到不同地方」这件事,CF 自己做不到。

出路是让这个域名的权威落在支持线路的 DNS 服务商(这里用 DNSPod)。但这样一来 CF 就不管这个名字了,橙云、缓存、WAF 全部失效——于是再用 Cloudflare for SaaS 把其中一条线路带回 CF:它的特点正是「DNS 不在 CF 也能让 CF 代理这个主机名」。

两种接入方式

委派模式 直托模式
前提 主域名在 CF,只想挪走一个子域名 域名的 NS 本来就指着 DNSPod
要做的 在 CF 加 NS 记录把子域名委派出去,还要清掉父区里被遮蔽的旧记录 什么都不用委派
能配什么 被委派的那个子域名 根域名本身,或它下面任意子域名
【委派模式】example.com (Cloudflare)
    ├── www / mail / 其它所有记录 ──> 照旧, 完全不受影响
    └── img  NS ──> DNSPod            ← 只有这一条被委派出去
                      │
                      ├── 境内线 ──> CNAME 国内 CDN / 优选域名
                      └── 默认线 ──> CNAME SaaS 区的橙云记录 ──> CF 边缘 ──> 源站

【直托模式】example.com (NS 直接指着 DNSPod)
    └── 任意记录天生支持线路, 不需要委派这一步

委派模式下能挪走的必须是子域名——域名本身(zone apex)的 NS 由注册商控制,不是 CF 区里能加的记录。直托模式没这个限制,根域名可以直接配。

两种模式在工具里共用同一套步骤、巡检和拆除机制,差别只在「父区相关的东西存不存在」:直托模式不会出现清理父区、NS 委派这些步骤,其余(自定义主机名、验证 TXT、证书、线路记录)完全一致。

准备:一个 也在 CF 的域名做 SaaS 区(自定义主机名不能和 SaaS 区同名,所以它必须是另一个域名)、一个 DNSPod 账号;走委派模式还要主域名在 CF。


准备 · 登录

首次打开要用 CZL Connect 账号登录一次。点登录会跳到系统浏览器完成授权,点完同意就自动回到应用,登录态存在本机,之后开着就不用再登。

登录纯粹是为了统计有多少人在用,除此之外没有任何作用。 域名、API 密钥、解析记录、巡检结果一概不上传——它们只写在本机那个 SQLite 文件里,程序全程只和 Cloudflare、腾讯云以及你自己的浏览器打交道。授权流程本身只从 CZL Connect 取回昵称、头像、邮箱这些账号资料,方向是单向的。它也不监听任何端口。

两个可能碰到的现象:

  • 授权页点完同意,浏览器那个标签页停在原地不动——正常,直接关掉。
  • 浏览器授权完却没回到应用——说明 splitdns:// 协议没注册上(换过安装目录、或被安全软件拦下)。把地址栏里那条 splitdns://callback 开头的地址整条复制回登录页,一样能完成登录。

第一步 · 凭据

「凭据」页各加一条。密钥保存后不再回显,只能覆盖。

平台 要什么 权限
Cloudflare API Token Zone:ReadDNS:EditSSL and Certificates:Edit;作用范围要同时覆盖父区和 SaaS 区
腾讯云 DNSPod SecretId / SecretKey DNSPod 读写

填完点「检测」。Cloudflare 会把这份 Token 能看到的 zone 全部列出来——Token 有效和权限范围够用是两回事,列表里没有你要用的 zone 就是白搭。

CF 凭据可以加多份。哪个域名归哪个账号是客观事实,不用你手动指定:后面填域名和回源时,程序拿名字去所有 CF 账号里找管辖它的 zone(最长后缀匹配),自己把账号定下来。


第二步 · 回源

「回源」页登记那些会被多个域名共用的落点,以后换机器只改这一处。只给一个域名用的(比如 EdgeOne 那种一域名一 CNAME),配域名时直接填就行,不必先来这里建。

四个类型里,最容易配反的是前两个:

「CF SaaS 落点」和「CF SaaS 自定义源」的区别

这两个描述的是回源链路上完全不同的两段

用户 ──解析──> [CF SaaS 落点] ──> CF 边缘 ──> [CF SaaS 自定义源] ──> 你的机器
        ↑                                   ↑
     DNS 记录的值                    自定义主机名上的一个字段

CF SaaS 落点 —— 它是 DNS 里那条 CNAME 的值,决定「流量怎么进 CF」。填 SaaS 区里任意一条橙云记录的主机名即可,不必非得是被设为「回退源」的那一条:流量到了 CF 边缘是按 Host 头去找自定义主机名的,CNAME 目标只负责把流量带进这个区。留空则用该区当前的回退源。

CF SaaS 自定义源 —— 它不是解析目标,而是配在 CF 自定义主机名上的 custom_origin_server,决定「流量进了 CF 之后往哪台机器转」。默认所有自定义主机名都回源到该区的回退源;只有当这个域名要走另一台机器时才需要它。

所以:

  • 只是「海外走 CF,回源到默认那台机器」→ 只要落点
  • 「海外走 CF,但这个域名要回源到另一台机器」→ 两个都要:落点把流量带进 CF,自定义源告诉 CF 转给谁

把自定义源填进 DNS 里是个常见错误——CF 根本不认识那个名字,请求进不了你的自定义主机名。

落点在 CF 上有没有真的落地

这是最坑的一处:落点也好、自定义源也好,只要写的是主机名,CF 那边就必须真有一条同名的橙云记录指向源站,流量才转得出去。CF 明文要求自定义源服务器是本账号 DNS 里的一条橙云记录,不能填 IP。

坑在于缺了这条记录、或者建成了灰云,回源直接失败,而自定义主机名页面上主机名状态、证书状态照样显示「有效」,从那边一点异常都看不出来。

回源页现在会自己去查,并直接给结论:

  • 记录不存在 → 一键建成橙云记录(填了「源站 IP」的话)
  • 已经存在 → 原样保留,绝不覆盖:那是线上正在生效的解析
  • 那份 CF 凭据读不到 zone 列表 → 明确报「无法判定」,而不是当成「不归我们管」悄悄跳过

「源站 IP」支持逗号分隔的双栈:IPv4 建 A、IPv6 建 AAAA,同名两条是正常的,不会互相误报。

巡检里也多了对应的两项:saas.custom_origin_record_missing(缺记录)和 custom_origin_record_grey(建成灰云了)。

另外两个类型没什么歧义:第三方 CDN / 优选域名 CNAME 填对方给的加速 CNAME 或你自己的优选域名,直连源站 IP 就是不过任何 CDN 直接落到 IP(优选 IP 也用这一类)。


第三步 · 域名

「域名 → 新增域名」,要填的东西比以前少:

  • 接入方式——「从 CF 父区委派子域名」或「DNSPod 直托根域名」
  • 访问域名——打前缀 + 从下拉里选后缀。委派模式的后缀来自 CF 的 zone 列表,直托模式来自 DNSPod 的域名列表;直托模式前缀留空就是根域名本身。选不到就退回手打整串
  • SaaS 区——从下拉里选;这条线不走 CF 就选「不使用 CF for SaaS」
  • DNSPod 凭据——只有一份时自动选中
  • 线路落点——每条线路指一个落点,可以引用回源库,也可以直接填

Cloudflare 凭据不用选了:填完访问域名,程序自己反查它落在哪个 CF 账号的哪个区(父区也是这么推导出来的,输入框下面会显示结果)。只有 SaaS 区恰好在另一个账号下时,才会单独记一份它的凭据。

:warning: 「默认」线是兜底,务必配上。只配境内 + 境外的话,识别不出归属的解析器会一条记录都拿不到。建议把覆盖面最广的那条挂在「默认」上。

DNSPod 免费版只有 默认 / 境内 / 境外 三条线路,要精确到某个国家得升级套餐。

优选怎么配

优选就是一条普通线路,没有专门的开关:类型选「第三方 CDN / 优选域名 CNAME」,落点值填你自己的优选域名;优选 IP 就用「直连源站 IP」建 A 记录。流量经优选域名进入 CF 边缘后,照样按 Host 头匹配到你的自定义主机名,所以优选线同样依赖 SaaS 区那套配置,不是绕开 CF。

:warning: 别把优选域名建成「CF SaaS 落点」。那一类会被「设置回退源」那一步当成本区回退源的候选,而优选域名根本不在你的 SaaS 区里,设上去会把回源打断。

一个典型配法——example.com 直托在 DNSPod,默认线走 CF、境内线走优选:

线路 类型 落点值
默认 CF SaaS 落点 origin.mycdn.net
境内 第三方 CDN / 优选域名 CNAME 你的优选域名

第四步 · 跟着流程走

保存后自动进入配置流程。每一步下面的按钮:

按钮 含义
自动执行 程序调 API 替你做
我自己做完了 你在 CF / DNSPod 面板里做完后点,等待计时从这一刻开始
确认完成 只出现在程序验不了的步骤(比如源站的 SNI 路由)

不管哪种方式,做完都会重新去三个平台核对一遍。平台接口返回成功不算数,巡检查到真的生效才算完成。所以:

  • 关掉程序隔天回来,进度还在,而且会按当前真实状态重新判定
  • 已经通过的步骤如果线上被人改了,会自动退回「等待生效」并说明差在哪
  • 清理父区旧记录那步会先列出每一条,点确认才动手

等 DNS 或证书生效的步骤会挂在「等待生效」,并写明还差什么、大约要等多久:

清理那一步默认给的是「先迁移到 DNSPod 再删」——被遮蔽不等于该扔,那些记录本来在正常服务,只是委派之后待错了地方。它会逐条判断:接入域名本身只删不搬(落点归线路配置管),其余原样搬走。橙云记录会单独提示,因为搬到 DNSPod 之后就不再经过 CF 了。

域名多了以后不用挨个点进去看:列表页每张卡片上直接显示各条流程走到哪了。这个进度取自本地库里的步骤状态,列表页一个平台接口都不调,不会因为域名多就变慢或者吃掉 API 配额。


不想要了:拆除

以前只能删本地记录,平台上的解析、证书、域名全留着,得自己去三个面板一处处翻。现在详情页多了个拆除 tab,用的还是配置流程那套步骤机制,每步先列清单再动手:

撤委派 → 清 DNSPod 记录 → 删 DNSPod 域名 → 删自定义主机名 → 清回退源 → 清父区验证记录

顺序不是随便排的。第一步必须是撤委派:反过来先删 DNSPod 域名的话,委派还指着不再托管它的 NS,解析器拿到的是 SERVFAIL 而且会一直重试,比干脆查不到更糟。

几条安全线:

  • 只删本工具维护的记录——认的是「声明过线路的落点」加上两条确切名字的验证 TXT,不按「位置 + 类型」泛认。直托模式那个区里全是你自己的解析,泛认会把别人的记录送进待删清单
  • 直托模式压根不生成「删 DNSPod 域名」这一步——那是你根域名的整个 DNS,连「跳过一下」的机会都不该给
  • 回退源是 SaaS 区共享的,区里还有别的自定义主机名指着它就直接拒绝执行,不给「确认一下就删」的机会——那些主机名会跟着一起失效
  • 删自定义主机名时会顺带清掉本工具为它建的那条落点记录,但有别人在用、或者它本身就是回退源时不动
  • 每步都能跳过,跳过还能撤销。想留着 DNSPod 域名、回退源还有别人在用,都是合理的「这步不做」
  • 拉取失败不会被当成「已经清干净」——空快照和真的读不到长得一模一样,不区分就会谎报成功

删本地记录留在流程外面(放进去的话删完流程自己也没了),在域名详情页直接删。


几个不看文档就会踩的坑

委派后留在父区的记录会变成 shadowed records。 它们在 CF 面板里看得见,但一条都不生效。排查时最容易被带偏——以为配了,其实没生效。

自定义源服务器必须是本账号 DNS 里的一条橙云记录。 缺了或建成灰云,回源直接失败,而自定义主机名页面照样显示一切正常。见第二步「落点在 CF 上有没有真的落地」。

用了自定义源,源站还必须能路由那个 SNI。 CF 回源时 Host 头是访问域名,但 TLS 握手用的 SNI 是源服务器名字,源站上的 Traefik / Nginx 匹配不到对应 router 就直接 403——跟证书、跟后端服务都没关系。工具在那一步会给出具体到机器、名字和自检命令的指令。

CF 的验证 TXT 可能是同名多条。 证书带通配符 SAN 时,基础域名和通配符各要一条 DCV,主机记录同名、值不同。少写一条证书就签不出来,而且报错不会告诉你少了哪条。

DNSPod 新加的域名默认是暂停状态。 这时候委派、记录可以全对,解析就是不出结果。工具会自动开启,也会在巡检里单独报出来。

主域名不在同一个腾讯云账号下时,加子域名要先验证归属。 DNSPod 会报 QuhuiTxtNotMatch,要在主域名(还在 CF 那个)上加一条 TXT。工具会自动取值、写进 CF、再重试。

TTL 最低 600。 DNSPod 免费版的下限,填更小会被接口直接拒。


巡检

配完之后,随时可以回来核对三个平台的实际状态。它专门盯这些地方:

  • 父区里被委派遮蔽的记录(直托模式没有这一项)
  • CF 要的验证 TXT 少没少
  • CF 那条有没有挂在「默认」线兜底
  • 自定义源那条橙云记录在不在、是不是灰云
  • DNSPod 上域名是不是还处于暂停状态
  • 委派的 NS 与 DNSPod 实际分配的对不对得上(直托模式则是 DNSPod 报 DNS_ERROR 时提醒 NS 可能没指过来)
  • 证书状态、到期时间、自定义源服务器是否与配置一致

上图那条提醒就是前面说的 SNI 那个坑——它会算出要去哪台机器、加哪个名字,并给出自检命令。这一项程序验不了,得你自己确认。

下面「实际状态」和「DNSPod 解析记录」是原样拉回来的现状,出问题时对着看比翻两个控制台快。

存量域名建议也都录进来。照样建条目、填线路,进流程会发现每一步都已完成,直接当巡检面板用。


换机器 / 备份

「数据」页可以整库导出和导入。导出的是一致性快照,导入前会自动把现有数据另存一份备份。

导出文件里有明文的平台密钥,当作密钥文件对待,别随手丢共享盘。

导出的副本里不含登录账号——那份令牌是身份不是业务数据,拿到手就能以本人身份调 CZL Connect。所以换台机器导入之后,重新登录一次即可,平台凭据和域名配置都还在。


下载

Releases · woodchen-ink/splitdns · GitHub

  • Windows 安装版 *-installer.exe —— 数据在 %APPDATA%\splitdns,升级重装不动它
  • Windows 绿色版 *-portable.zip —— 解压即用,数据在 exe 同级 data/,整个文件夹拷走就带走全部配置
  • macOS *-macos-universal.zip —— Intel 与 Apple Silicon 通用,数据在 ~/Library/Application Support/splitdns

Windows 上没有 WebView2 会自己拉起来装。macOS 版没做签名公证,首次打开会被 Gatekeeper 拦:右键点 .app → 打开 → 再点一次「打开」,或者 xattr -dr com.apple.quarantine splitdns.app

源码在 github.com/woodchen-ink/splitdns(MIT),Windows 与 macOS 的包都由 GitHub Actions 打 tag 自动构建。