☰
DDNS 项目 Cloudflare 服务商配置指南:API Token 认证、proxied 匹配逻辑与 TTL 策略
2026/10/14 15:33:45 网站建设 项目流程
  • 网络
  • CLI

【免费下载链接】DDNS

🌐自动更新域名解析到本机IP,支持dnspod,阿里DNS,CloudFlare,华为云,DNSCOM...

项目地址:https://gitcode.com/gh_mirrors/dd/DDNS
点击查看免费下载

Cloudflare 是 DDNS 项目(自动更新域名解析到本机 IP)支持的主流 DNS 服务商之一。本文基于仓库中的 Cloudflare 服务商文档,结合 ddns/provider/cloudflare.py 的实现与 tests/test_provider_cloudflare.py 的测试用例,完整讲解 Cloudflare API Token / Global API Key 两种认证方式的配置方法、proxied代理状态的记录匹配回退逻辑、ttl在不同套餐下的取值规则,以及失败重试与缓存机制的底层行为。读完本文,你可以独立完成 Cloudflare 服务商的接入配置,并能理解 DDNS 是如何调用 Cloudflare API v4 完成记录的查询、创建与更新的。

服务概述与项目集成方式

Cloudflare 提供权威 DNS 解析服务,支持通过 API 动态创建和更新 DNS 记录。DDNS 项目通过 Cloudflare API 对 DNS 记录进行自动管理:获取本机最新公网 IP 后,自动查找、更新或创建对应的 A/AAAA 记录。

在仓库中,Cloudflare 适配由 ddns/provider/cloudflare.py 中的CloudflareProvider类实现,它继承自 ddns/provider/_base.py 的BaseProvider抽象基类。从类常量可以看到项目的集成方式:

  • endpoint = "https://api.cloudflare.com":Cloudflare API v4 的默认端点;
  • content_type = TYPE_JSON:请求体使用 JSON 编码;
  • _require_http_success = True:开启严格 HTTP 成功检查,非 2xx 状态一律视为失败(这是本文"错误处理与缓存"一节的关键)。

配置文件中的dns字段使用cloudflare作为服务商标识,该取值定义在 schema/v4.1.json 的enum中,可用 JSON 配置的$schema字段获得编辑器校验。

认证配置

DDNS 对 Cloudflare 支持两种认证方式,二者的区别体现在请求头构造上。CloudflareProvider._request()中的逻辑是(见 ddns/provider/cloudflare.py#L24-L40):

  • 配置了id(邮箱)时,使用X-Auth-Email+X-Auth-Key请求头(Global API Key 模式);
  • 未配置id时,使用Authorization: Bearer <token>请求头(API Token 模式)。

1. API Token 认证(推荐)

API Token 方式更安全,支持精细化权限控制,是 Cloudflare 推荐的集成方法。

获取步骤:

  1. 登录 Cloudflare 控制台(dash.cloudflare.com);
  2. 进入 "My Profile" > "API Tokens",或直接访问dash.cloudflare.com/profile/api-tokens;
  3. 点击 "Create Token",选择Custom token模板;
  4. 配置权限:Zone:Read和Zone:DNS:Edit(下文权限章节详述);
  5. 选择要管理的域名 zones;
  6. 复制生成的API Token。令牌只显示一次,请妥善保存。

对应配置(id留空或不填):

{ "dns": "cloudflare", "token": "your_cloudflare_api_token" // Cloudflare API Token, ID 留空或者不填 }

2. Global API Key 认证(不推荐)

使用 Cloudflare 账户邮箱和 Global API Key,权限过大、安全性较低,仅建议在特殊场景使用。

获取步骤:

  1. 登录 Cloudflare 控制台;
  2. 进入 "My Profile" > "API Tokens";
  3. 查看 "Global API Key" 并复制。

对应配置:

{ "dns": "cloudflare", "id": "your-email@example.com", // Cloudflare 账户邮箱 "token": "your_global_api_key" // Cloudflare Global API Key }

认证校验规则(源码级)

在构造 provider 实例时,_validate()会执行以下校验(ddns/provider/cloudflare.py#L15-L22):

  • token为必填,缺失时抛出ValueError: token must be configured;
  • 如果填写了id,其中必须包含@字符(Cloudflare API v4 要求它是账户邮箱),否则抛出ID must be a valid email or Empty for Cloudflare API v4。

这些规则在 tests/test_provider_cloudflare.py 中有对应单测:test_validate_failure_no_token验证缺失 token 报错,test_validate_failure_invalid_email验证非法邮箱报错,test_request_with_bearer_auth与test_request_with_email_auth分别验证了两种请求头模式。

权限要求

确保使用的 Cloudflare 账号具有以下权限:

API Token 权限

  • Zone:Read:区域读取权限,用于列出和获取域名区域信息。项目实际使用的对应调用是GET /client/v4/zones(带name.exact精确匹配参数);
  • Zone:DNS:Edit:DNS 编辑权限,用于创建、更新和删除 DNS 记录。对应调用是POST /client/v4/zones/{id}/dns_records(创建)和PUT /client/v4/zones/{id}/dns_records/{record_id}(更新)。

Global API Key 权限

  • Full Access(完全访问):拥有账户下所有资源的完全控制权限,这也是该方式不被推荐的原因。

你可以在 Cloudflare 控制台的 API 令牌管理页面查看和配置权限。

完整配置示例

一个典型的 Cloudflare 配置文件如下(完整字段说明见 JSON 配置参考):

{ "$schema": "https://ddns.newfuture.cc/schema/v4.1.json", // 格式验证 "dns": "cloudflare", // 当前服务商 "token": "your_cloudflare_api_token", // Cloudflare API Token "index4": ["url:http://api.ipify.org", "public"], // IPv4地址来源 "index6": "public", // IPv6地址来源 "ipv4": ["ddns.newfuture.cc"], // IPv4 域名 "ipv6": ["ddns.newfuture.cc", "ipv6.ddns.newfuture.cc"], // IPv6 域名 "ttl": 300, // DNS记录TTL(秒) "proxied": false // 是否启用 Cloudflare 代理 }

参数说明

参数说明类型取值范围/选项默认值参数类型
dns服务商标识字符串cloudflare无服务商参数
id认证邮箱字符串Cloudflare 账户邮箱(仅 Global API Key)无服务商参数
token认证密钥字符串Cloudflare API Token 或 Global API Key无服务商参数
index4IPv4 来源数组参考配置default公用配置
index6IPv6 来源数组参考配置default公用配置
ipv4IPv4 域名数组域名列表无公用配置
ipv6IPv6 域名数组域名列表无公用配置
ttlTTL 时间整数(秒)参考下方300/auto服务商参数
proxied代理状态布尔true、false无服务商参数
proxy代理设置数组参考配置无公用网络
sslSSL 验证方式布尔/字符串"auto"、true、falseauto公用网络
cache缓存设置布尔/字符串true、false、filepathtrue公用配置
log日志配置对象参考配置无公用配置

参数类型说明:

  • 公用配置:所有支持的 DNS 服务商均适用的标准 DNS 配置参数;
  • 公用网络:所有支持的 DNS 服务商均适用的网络设置参数;
  • 服务商参数:当前服务商支持,值与当前服务商相关。

proxied是如何传递给服务商 API 的

proxied不是 JSON Schema 中的标准字段,而是通过 DDNS 的extra 机制透传给服务商。从 schema/v4.1.json 可以看到extra对象的官方示例正是 Cloudflare 的proxied、comment、tags等字段。

其传递链路可以从源码确认:

  1. 配置加载阶段,ddns/config/config.py 的_collect_extra()会收集所有不属于已知键(dns、token、ttl等)的字段。因此在 JSON 配置顶层直接写"proxied": false会被自动归入config.extra;也可以使用显式的extra对象写法(如"extra": {"proxied": true}),或在命令行/环境变量中使用extra_proxied前缀。优先级为CLI > JSON > ENV;
  2. 执行阶段,ddns/main.py 的update_ip()调用dns.set_record(domain, address, record_type=..., ttl=config.ttl, line=config.line, **config.extra),把proxied作为extra参数展开传入 provider;
  3. provider 层的_query_record/_create_record/_update_record从extra中读取并使用它(见下文)。

这一机制由 tests/test_config_extra.py 覆盖,例如test_extra_from_json_undefined_fields验证了顶层未定义字段会进入extra。

proxied:Cloudflare 代理状态与记录匹配逻辑

proxied参数控制 DNS 记录是否通过 Cloudflare 代理(橙色云 / Orange Cloud)。这是 Cloudflare 特有的功能,用于启用或禁用其 CDN 和安全保护功能。

查询记录匹配逻辑

当配置了proxied参数时,DDNS 会按照以下优先级查询现有的 DNS 记录:

  1. 优先使用proxied过滤:首先尝试查询匹配指定proxied状态的记录;
  2. 回退到无过滤查询:如果带proxied过滤的查询没有找到记录,将自动重试不带proxied过滤的查询。

这种回退机制确保了以下场景的正确处理:

  • 场景 1:配置文件从"proxied": true改为"proxied": false—— 即使原记录是proxied=true,系统也能找到并更新它;
  • 场景 2:配置文件从"proxied": false改为"proxied": true—— 即使原记录是proxied=false,系统也能找到并更新它;
  • 场景 3:配置文件新增"proxied": true/false参数 —— 能够找到不带proxied过滤创建的记录并进行更新。

注意:如果查询时带proxied过滤找到了记录,则不会执行回退查询,直接使用匹配的记录。

源码实现印证

上述逻辑完整实现在_query_record()中(ddns/provider/cloudflare.py#L52-L85):

  • 查询使用name.exact(完整域名精确匹配,由join_domain(sub, main)拼接)加type过滤,per_page=10000一次性拉取;
  • 如果extra中带proxied,布尔值会先转换为小写字符串(True -> "true",False -> "false")作为查询参数,符合 Cloudflare API 的过滤参数格式;
  • 第一轮过滤查询未命中且配置了proxied时,发起第二轮仅按name.exact的查询;
  • 最终在客户端再次按name与type双条件确认匹配记录,避免同名不同类型的记录误匹配。

tests/test_provider_cloudflare.py 对回退行为做了精确断言:test_query_record_with_proxy_false_fallback和test_query_record_with_proxy_true_fallback验证了两次请求的先后顺序与参数(第一次带proxied: "false"/"true",第二次不带);test_query_record_with_proxy_found_with_filter验证了命中过滤条件时只发起一次请求;test_query_record_no_extra_filter验证了未配置proxied时不存在回退请求。

更新记录时的代理状态保留

_update_record()(ddns/provider/cloudflare.py#L101-L120)在发起PUT更新时有默认保留策略:extra中显式提供的proxied、tags、settings优先;未提供时,回退沿用old_record中原有的proxied、tags、settings值,避免更新 IP 时意外改变记录的代理状态或元数据。comment则默认写入 remark(Managed by [DDNS](https://ddns.newfuture.cc)),可通过extra.comment自定义。对应的单测是test_update_record_preserves_old_values与test_update_record_with_extra_params。

ttl:TTL 取值规则

ttl参数指定 DNS 记录的生存时间(TTL),单位为秒。Cloudflare 的 TTL 设置根据记录是否启用代理而有所不同。

代理记录(Proxied Records)

所有代理记录的 TTL 默认为Auto,固定为300 秒(5 分钟),此值无法编辑。

由于只有用于 IP 地址解析的记录才能被代理,此设置确保分配的任播 IP 地址的潜在变化能够快速生效,因为递归解析器不会将其缓存超过 300 秒。

注意:实际体验记录变化可能需要超过 5 分钟,因为本地 DNS 缓存可能需要更长时间才能更新。

非代理记录(Unproxied Records)

对于仅 DNS 记录,你可以选择以下 TTL 范围:

套餐类型支持的 TTL 范围(秒)说明
Free/Pro/Business60 - 86400最低 TTL 为 1 分钟
Enterprise30 - 86400最低 TTL 为 30 秒

TTL 设置为Auto时固定为300 秒(5 分钟)。

在 DDNS 侧,ttl为空时对应 provider 调用中ttl=None,由 Cloudflare 采用其默认策略(即 Auto/300 秒的行为);配置了具体数值时,该值会作为ttl参数直接传给创建/更新 API。注意创建或更新请求中None参数会被_request()自动过滤掉,不会以null形式发送给 API。

运行工作流:从域名到 API 调用

理解了参数之后,可以从源码看清一次完整的同步流程。ddns/provider/_base.py 中BaseProvider.set_record()(L339-L385)定义了统一流程:

  1. 域名拆分:优先识别sub~main/sub+main的自定义分隔符格式;否则从右向左逐级尝试主域名(如a.b.example.com会先尝试example.com),直到get_zone_id()查到 zone,从而支持账户下存在多个 DNS 区域的情况;
  2. Zone 缓存:get_zone_id()将查询结果缓存到_zone_map,同一次运行中重复域名不会重复调用 zone 列表接口;
  3. 记录查询:调用_query_record()(含前文的proxied过滤与回退);
  4. 更新或创建:找到记录走_update_record()(PUT),否则走_create_record()(POST)。

CloudflareProvider._query_zone_id()(ddns/provider/cloudflare.py#L42-L50)通过GET /client/v4/zones并带name.exact参数查询,然后在结果中做精确名称比对后返回id。测试用例test_full_workflow_create_new_record与test_full_workflow_update_existing_record模拟了"查 zone → 查记录 → 创建/更新"三次完整 API 调用的顺序与参数,可作为实际请求序列的参照。

故障排除

调试模式

启用调试日志查看详细信息:

ddns -c config.json --debug

常见问题

  • Invalid API token:检查 API Token 是否正确,确认权限配置;
  • Zone not found:确保域名已添加到 Cloudflare 账号,域名处于活跃状态;
  • Record creation failed:检查记录格式和 TTL 值,确认权限设置;
  • Rate limit exceeded:API 调用频率超限,降低请求频率。

错误处理与缓存

Cloudflare 请求只有在HTTP 状态为 2xx 且 API 返回success: true时才被视为成功。这条规则在源码中体现为两层:

  • _request()中,只有data.get("success") is True才返回result(成功的空列表仍合法地表示"没有匹配记录");其他情况记录errors并抛出RuntimeError。注释明确写道:"Do not let a failed lookup become an empty result and trigger record creation."(不能让失败的查询变成空结果进而触发记录创建);
  • 基类_http()对 400/401/403/5xx 直接抛异常;而_require_http_success = True使 429 等非 2xx 状态同样被拒绝,即使响应体里写着success: true也无效。

由此产生的缓存语义是:

  • 最终收到 HTTP 429 等错误状态、API 返回success: false或无效响应时,本次域名更新失败,不会将待更新的 IP 写入成功缓存,后续同步仍会重试;
  • 区域(zone)或记录查询失败会终止当前域名的处理,不会被当作"记录不存在"而创建新记录;而成功查询返回空记录列表时,仍会正常进入创建流程。

这些语义由 tests/test_provider_cloudflare.py 的TestCloudflareProviderHTTPResponses测试类(L673-L808)逐一验证,例如:test_create_rate_limit_is_not_cached(429 后缓存文件为空{},下一轮重试成功并写入domain:A -> 地址)、test_http_failure_overrides_success_envelope(429 状态下即使响应体是success: true也判失败)、test_record_query_failure_does_not_create(记录查询失败后不发起 POST 创建)、test_filtered_query_failure_does_not_fallback(带proxied过滤的查询失败时不回退重试,直接终止)、test_successful_empty_record_list_creates(空记录列表正常触发创建)。

延伸资料与仓库参考

  • 中文版文档:Cloudflare DNS 配置指南(与本文对应);
  • 其他服务商文档:服务商文档列表;
  • 完整 JSON 配置参数:JSON 配置文件参考;
  • 配置模式定义:schema/v4.1.json(dns、extra字段定义);
  • 核心实现:ddns/provider/cloudflare.py、ddns/provider/_base.py;
  • 行为验证测试:tests/test_provider_cloudflare.py;
  • Cloudflare 侧资料:Cloudflare 开发者文档、Cloudflare API 参考、Cloudflare 控制台与社区支持(以 Cloudflare 官方渠道为准,本文不列外部链接)。

建议:推荐使用 API Token 方式,支持精细化权限控制,提升账号安全性,避免使用 Global API Key。

  • 网络
  • CLI

【免费下载链接】DDNS

🌐自动更新域名解析到本机IP,支持dnspod,阿里DNS,CloudFlare,华为云,DNSCOM...

项目地址:https://gitcode.com/gh_mirrors/dd/DDNS
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询