简介与原理
Introduction & Architecture
cf-ddns 是「按运营商线路优选 Cloudflare 节点 + 智能 DNS 更新」工具:纯 Go 标准库实现,零依赖,编译后是单文件二进制,开箱即用。
背景:Cloudflare anycast IP 在国内不同运营商下的质量差异很大——对移动最快的 IP,对电信可能很慢。常见做法是定期测速、更换 IP,但一条 DNS 记录只能有一个值,无法同时满足三家运营商。
做法:cf-ddns 为每条运营商线路(默认 / 移动 / 联通 / 电信)分别优选节点,再借助 DNSPod 的线路解析能力,把同一个域名写成不同线路的解析记录。移动 / 联通 / 电信用户访问同一个域名,各自解析到自己线路最快的节点。
Cloudflare DNS 没有运营商线路维度,因此承载优选记录的域名需要托管到 DNSPod(免费套餐即可)。具体迁移 / 委派方式见「快速开始」第 1 步。
核心工作流
Pipeline · 每轮 6 步
每轮循环对所有线路执行以下 6 步;所有线路处理完毕后休眠 interval(默认 10 分钟)再开始下一轮。单条线路失败不影响其它线路。
优选「主槽位」在 A 记录与 CNAME 记录之间互斥;当主记录为 CNAME 时,目标域名自带双栈解析,因此跳过 AAAA 记录的维护。
选优策略
pick 策略对比
每种策略下,本机测速都只是「存活过滤」;区别在于从存活的候选中按什么顺序取第一名。
| 策略 | 选择方式 | 适用场景 |
|---|---|---|
order默认 |
本机测速仅用于存活过滤,在存活候选中取 BestCF 列表排名最靠前的 | 跨运营商线路:程序跑在电信机器上时,实测的移动线路延迟没有参考价值,应信任 BestCF 的全国多点测速排名 |
latency |
取本机实测建连延迟最低的候选 | 程序部署在与该线路相同运营商的网络中,本机测速结果可信 |
机器所在运营商与线路不匹配时,latency 的实测结果会失真(例如在电信网络里测出的「最优」移动 IP)。默认的 order 正是为此设计。
配置参考
字段表 + JSON 示例
配置文件为 JSON,必须使用 UTF-8 编码(线路名是中文)。下面按「通用字段 / lines 元素 / 服务商专属」三组说明。
通用字段
| 字段 | 类型 | 默认 | 说明 |
|---|---|---|---|
provider | string | cloudflare | dnspod:分线路模式;cloudflare:单记录兼容模式 |
record | string | — | 完整记录名,如 cf.example.com |
ttl | int | dnspod 600 / cloudflare 60 | DNS TTL |
interval | string | "10m" | Go duration 格式,一轮循环的休眠时长 |
task | int | 50 | 并发测速协程数 |
colo | string | 空 | 全局数据中心过滤,逗号分隔(如 HKG,NRT) |
ipv6 | bool | false | 是否优选 IPv6 并维护 AAAA 记录;需本机具备 IPv6 连通 |
dry_run | bool | false | 仅测速并输出结果,不写 DNS |
lines 元素
| 字段 | 类型 | 默认 | 说明 |
|---|---|---|---|
line | string | 必填 | 线路名:默认 / 移动 / 联通 / 电信,须与 DNSPod 的线路名一致 |
ips_url | string | 必填 | 候选列表地址(BestCF 下载) |
pick | string | order | order(信任 BestCF 排名)或 latency(本机实测最低) |
colo | string | 继承全局 | 线路级数据中心过滤,缺省继承全局 colo |
服务商专属
| provider | 字段 | 类型 | 说明 |
|---|---|---|---|
dnspod | secret_id | string | 腾讯云 API SecretId |
secret_key | string | 腾讯云 API SecretKey | |
domain | string | 域名,如 example.com | |
cloudflare | cf_token | string | API Token,需 Zone→DNS→Edit 权限 |
zone_id | string | Zone ID,在域名 Overview 页右下角 | |
proxied | bool | 是否开启代理(小黄云);直连优选场景应为 false |
JSON 示例(dnspod 分线路模式)
{
"provider": "dnspod",
"record": "cf.example.com",
"ttl": 600,
"interval": "10m",
"task": 50,
"colo": "HKG,NRT",
"ipv6": true,
"dry_run": false,
"secret_id": "AKID…",
"secret_key": "…",
"domain": "example.com",
"lines": [
{ "line": "默认", "ips_url": "https://github.com/DustinWin/BestCF/releases/download/bestcf/bestcf-ip.txt", "pick": "order" },
{ "line": "移动", "ips_url": "https://github.com/DustinWin/BestCF/releases/download/bestcf/cmcc-ip.txt", "pick": "order", "colo": "HKG,NRT" },
{ "line": "联通", "ips_url": "https://github.com/DustinWin/BestCF/releases/download/bestcf/cucc-ip.txt", "pick": "latency" },
{ "line": "电信", "ips_url": "https://github.com/DustinWin/BestCF/releases/download/bestcf/ctcc-ip.txt", "pick": "order" }
]
}
候选列表地址表
| 线路 | 文件名 | 完整地址 |
|---|---|---|
| 默认 / 通用 | bestcf-ip.txt | https://github.com/DustinWin/BestCF/releases/download/bestcf/bestcf-ip.txt |
| 移动 | cmcc-ip.txt | https://github.com/DustinWin/BestCF/releases/download/bestcf/cmcc-ip.txt |
| 联通 | cucc-ip.txt | https://github.com/DustinWin/BestCF/releases/download/bestcf/cucc-ip.txt |
| 电信 | ctcc-ip.txt | https://github.com/DustinWin/BestCF/releases/download/bestcf/ctcc-ip.txt |
| 优选域名(CNAME) | bestcf-domain.txt | https://github.com/DustinWin/BestCF/releases/download/bestcf/bestcf-domain.txt |
快速开始
Quick Start · 5 步
-
1
准备域名:托管到 DNSPod
Cloudflare DNS 没有运营商线路维度,承载优选记录的域名需托管到 DNSPod(免费套餐即可)。两种方案任选其一:
- 方案 A · 整域托管:把域名的 NS 记录改为 DNSPod 提供的
f1g1ns1.dnspod.net,整域迁入 DNSPod。 - 方案 B · 子域名委派:域名保留在 Cloudflare,为承载优选记录的子域名(如
cf.example.com)添加 NS 记录,指向 DNSPod。
验证:
nslookup -type=NS 你的域名,确认返回 DNSPod 的 NS 记录。 - 方案 A · 整域托管:把域名的 NS 记录改为 DNSPod 提供的
-
2
获取腾讯云密钥
腾讯云控制台 → 访问管理 → API 密钥管理,创建密钥。建议使用子账号并仅授权
QcloudDNSPodFullAccess,避免主账号密钥泄露造成过大影响。 -
3
写配置
复制示例配置并按需修改。配置文件必须为 UTF-8 编码——线路名是中文,切勿用 GBK / ANSI 保存。
bash初始化配置cp config.example.json config.json # 编辑 config.json,填入 record / secret_id / secret_key / domain / lines -
4
构建并试运行
先编译,再用
-dry-run观察输出;确认无误后正式运行。bash构建与试运行go build -o cf-ddns . ./cf-ddns -config config.json -dry-run # 仅测速,不写 DNS ./cf-ddns -config config.json # 正式运行 -
5
命令行参数
参数 说明 -config配置文件路径 -cf-tokenCloudflare API Token -zone-idCloudflare Zone ID -record完整记录名 -proxied是否开启代理(小黄云) -ttlTTL -interval循环间隔(Go duration,如 "10m")-ips-url候选列表地址 -colo数据中心过滤(逗号分隔) -task并发测速协程数 -ipv6启用 IPv6 优选 -dry-run仅测速,不写 DNS 其中
-dry-run与-ipv6在显式传入时会覆盖配置文件中的对应值。
部署(systemd)
Linux 常驻部署
-
1
交叉编译
在本机交叉编译出 Linux amd64 二进制(也可直接换成目标机器的架构)。
bash交叉编译GOOS=linux GOARCH=amd64 go build -o cf-ddns . -
2
传输与安装
配置里包含密钥,务必通过
scp/sftp等加密通道传输。二进制放/usr/local/bin,配置放/etc/cf-ddns/config.json并设为 600。bash传输与安装scp cf-ddns config.json user@server:/tmp/ sudo install -m 0755 /tmp/cf-ddns /usr/local/bin/cf-ddns sudo mkdir -p /etc/cf-ddns sudo install -m 600 /tmp/config.json /etc/cf-ddns/config.json -
3
创建 systemd unit
ini/etc/systemd/system/cf-ddns.service[Unit] Description=cf-ddns Cloudflare 优选 IP 动态 DNS After=network-online.target Wants=network-online.target [Service] Type=simple ExecStart=/usr/local/bin/cf-ddns -config /etc/cf-ddns/config.json Restart=always RestartSec=10 ProtectSystem=strict ProtectHome=read-only NoNewPrivileges=true PrivateTmp=true [Install] WantedBy=multi-user.target -
4
注册并启动
bash启用与查看日志sudo cp cf-ddns.service /etc/systemd/system/ sudo systemctl daemon-reload sudo systemctl enable --now cf-ddns journalctl -u cf-ddns -f
配置文件含密钥:scp 请走加密通道;落地后权限保持 600,勿用明文传输或随意改权限。
验证方法
Verification
-
1
在线多点测试
在
itdog.cn/dns输入域名做多点 DNS 解析,三网(移动 / 联通 / 电信)的差异一目了然。 -
2
本机解析
在服务器或本机执行
nslookup cf.example.com,应返回当前宽带运营商线路的解析结果。
不要指定其它运营商的公共 DNS 来「验证」——由于 EDNS 与出口 IP 拦截问题,指定其它运营商公共 DNS 的结果不可靠,不能代表目标线路的真实解析。
常见问题
FAQ
Q1提示「无存活 IPv6 候选」,怎么办?
原因是本机没有 IPv6 出口。这不影响 IPv4 线路,工具会自动跳过 AAAA 记录的维护。可用 curl -6 https://ip.sb 验证本机是否具备 IPv6 连通性。
Q2提示 TTL 低于下限,怎么处理?
DNSPod 免费套餐的最小 TTL 为 600 秒,把 ttl 调到 600 及以上即可。
Q3写入失败提示需要「默认」线路,为什么?
DNSPod 要求记录名下先存在「默认」线路的记录。工具已自动把「默认」线路排到处理最前,正常流程下无需手动干预。
Q4从配置里删掉了某条线路,线上记录还在?
工具只收敛自身维护的记录,不会自动删除已存在的线上记录。删除线路后需到 DNSPod 控制台手动清理残留的线路记录。
Q5cloudflare 模式提示不支持线路,怎么办?
Cloudflare DNS 不支持按运营商线路解析,无法承载多线路记录。请改用 dnspod 模式,并把域名托管到 DNSPod(见第 05 节)。
兼容模式
Cloudflare 单记录模式
provider=cloudflare 是「单记录模式」:不需要分线路时的旧版行为,旧配置无需任何修改即可继续使用。要点:
- 仅允许
默认线路,不维护运营商多线路。 - TTL 默认
60。 - Token 需 Zone→DNS→Edit 权限;Zone ID 在域名 Overview 页右下角。
- 直连优选场景下
proxied应为false。
{
"provider": "cloudflare",
"record": "cf.example.com",
"ttl": 60,
"cf_token": "…",
"zone_id": "…",
"proxied": false
}