An octoDNS provider that targets Cloudflare.
pip install octodns-cloudflare
Pinning specific versions or SHAs is recommended to avoid unplanned upgrades.
# Start with the latest versions and don't just copy what's here
octodns==0.9.14
octodns-cloudflare==0.0.1
# Start with the latest/specific versions and don't just copy what's here
-e git+https://git@github.com/octodns/octodns.git@9da19749e28f68407a1c246dfdf65663cdc1c422#egg=octodns
-e git+https://git@github.com/octodns/octodns-cloudflare.git@ec9661f8b335241ae4746eea467a8509205e6a30#egg=octodns_cloudflare
providers:
cloudflare:
class: octodns_cloudflare.CloudflareProvider
# Your Cloudflare account email address (not needed if using token)
# setting email along with an API Token will raise an error.
email: env/CLOUDFLARE_EMAIL
# The API Token or API Key.
# Required permissions for API Tokens are Zone:Read, DNS:Read and DNS:Edit.
# Page Rules:Edit is required for managing Page Rules (URLFWD) records.
token: env/CLOUDFLARE_TOKEN
# Optional. Filter by account ID in environments where a token has access
# across more than the permitted number of accounts allowed by Cloudflare.
account_id: env/CLOUDFLARE_ACCOUNT_ID
# Import CDN enabled records as CNAME to {}.cdn.cloudflare.net. Records
# ending at .cdn.cloudflare.net. will be ignored when this provider is
# not used as the source and the cdn option is enabled.
#
# See: https://support.cloudflare.com/hc/en-us/articles/115000830351
#cdn: false
# Manage Page Rules (URLFWD) records
# pagerules: true
# Optional. Define Cloudflare plan type for the zones. Default: free,
# options: free, pro, business, enterprise
#plan_type: free
# Optional. Default: 4. Number of times to retry if a 429 response
# is received.
#retry_count: 4
# Optional. Default: 0. Number of times to retry if a 403 response
# is received.
#auth_error_retry_count: 0
# Optional. Default: 300. Number of seconds to wait before retrying.
#retry_period: 300
# Optional. Default: 50. Number of zones per page.
#zones_per_page: 50
# Optional. Default: 100. Number of dns records per page.
#records_per_page: 100
# Optional. Default: 120. Lowest TTL allowed to be set.
# A different limit for (non-)enterprise zone applies.
# See: https://developers.cloudflare.com/dns/manage-dns-records/reference/ttl
#min_ttl: 120
# Optional. Default: 15. Timeout in seconds for API requests.
#timeout: 15
# Optional. Default: https://api.cloudflare.com/client/v4. API base URL for Cloudflare API requests.
#api_url: https://api.cloudflare.com/client/v4
# Optional. Default: false. Enable when the zone has Cloudflare
# multi-provider DNS enabled, so that Cloudflare-managed apex NS records
# (absent from the DNS records API, only available via the zone's
# `name_servers`) are included when this provider is the source.
#
# See: https://developers.cloudflare.com/dns/nameservers/nameserver-options/#multi-provider-dns
#multi_provider: falseCloudflare Internal DNS (Enterprise, beta) hosts zones of type: "internal" whose records resolve only inside a private network via Cloudflare Gateway. CloudflareInternalProvider manages records inside pre-existing internal zones. Use it alongside CloudflareProvider so public and internal zones are each handled by the right provider instance:
providers:
cloudflare:
class: octodns_cloudflare.CloudflareProvider
token: env/CLOUDFLARE_TOKEN
account_id: env/CLOUDFLARE_ACCOUNT_ID
cloudflare_internal:
class: octodns_cloudflare.CloudflareInternalProvider
token: env/CLOUDFLARE_TOKEN
# Required. Internal DNS views are account-scoped.
account_id: env/CLOUDFLARE_ACCOUNT_ID
# Optional. Narrow zone enumeration to a single DNS view. Set this when
# two internal zones in the account share a name across different views
# (allowed by Cloudflare); the provider will otherwise raise at populate
# time listing the duplicate zone_ids.
#view_id: env/CLOUDFLARE_VIEW_ID
zones:
corp.internal.tests.:
sources: [config]
targets: [cloudflare_internal]Notes and constraints:
- Zones must pre-exist in Cloudflare. The provider does not auto-create internal zones (create them in the dashboard or via
POST /zoneswithtype: "internal", then link to a view). - Not supported (
cdn,pagerules,plan_type) — passing any of these toCloudflareInternalProviderraises an error. Cloudflare internal zones have no proxy, no pagerules, and no plan tier. - Root NS records are stripped before apply, with a warning logged. Internal zones have no nameservers (Cloudflare Gateway resolves them directly), so root NS records are never meaningful on this zone type. You can leave
NSrecords in a shared YAML source without reconfiguringstrict_supports. - Zone enumeration is hybrid by default: the provider takes the union of
GET /zones?account.id=…(filtered totype=="internal") and a walk of the account's DNS views (GET /accounts/{account_id}/dns_settings/views→ each view'szones[]→GET /zones/{zone_id}to hydrate names). Settingview_idnarrows enumeration to a single view. - Required token scopes: Account: DNS Views (Edit), Account: Account Settings (Edit), Zone: Zone (Read), Zone: DNS (Edit), Zone: DNS Settings (Edit). Include the account in Account Resources and the internal zones in Zone Resources.
- Cross-instance collisions are user-owned: if a zone is linked to multiple views and you register both views with octoDNS, both providers write to the same underlying zone. Split your octoDNS config so each zone is managed by exactly one provider.
Note: The "proxied" flag of "A", "AAAA" and "CNAME" records can be managed via the YAML provider like so:
name:
octodns:
cloudflare:
proxied: true
# auto-ttl true is implied by proxied true, but can be explicitly
# configured to be more complete
#auto-ttl: true
# with proxied=true, the TTL here will be ignored by CloudflareProvider
ttl: 120
type: A
value: 1.2.3.4Note: All record types support "auto" ttl, which is effectively equivalent to 300s.
name:
octodns:
cloudflare:
auto-ttl: true
# with proxied=true, the TTL here will be ignored by CloudflareProvider
ttl: 120
type: A
value: 1.2.3.4Note: Per-record CNAME flattening is opt-in for non-apex, non-proxied
CNAME records and requires a paid Cloudflare plan -- Cloudflare rejects the
setting outright on Free zones. Only add octodns.cloudflare.flatten_cname
when CloudflareProvider should manage this setting. If the key is omitted,
the provider leaves the current API state unchanged. Set it to true to
enable flattening or false to disable flattening.
The zone must not have zone-wide CNAME flattening enabled and the target must be outside the zone for the setting to take effect. The setting is unavailable for proxied records and has no effect at the zone apex because Cloudflare flattens apex CNAMEs regardless of this setting. Internal DNS applies CNAME flattening by default and the setting cannot be turned off.
cname:
octodns:
cloudflare:
flatten_cname: true
ttl: 120
type: CNAME
value: external.example.com.Note: All record types also support tagging, which can be combined with the tag processor to support advanced filtering scenarios.
name:
octodns:
cloudflare:
tags:
- "managed-by:terraform"
- "team:engineering"
ttl: 120
type: A
value: 1.2.3.4Note: Cloudflare stores comment and tags on each individual DNS object — that is, per value. The record-level comment/tags above are applied to every value of a record. To set them per value, add a values list under octodns.cloudflare, where each entry names a value (in the same form it appears in the record's values) and its own comment and/or tags:
multi:
octodns:
cloudflare:
comment: "default applied to values without an entry"
tags:
- "team:web"
values:
- value: 1.2.3.5
comment: "failover box"
tags:
- "team:web"
- "deprecated"
ttl: 300
type: A
values:
- 1.2.3.4 # uses the record-level comment/tags above
- 1.2.3.5 # uses its own entryA value's entry is a clean override: a comment/tags it specifies replaces the record-level one for that value (tags are not merged), while a field it omits falls back to the record level. Records whose values all share the same metadata keep the simpler record-level form shown earlier. Structured-value types work the same way — the entry's value is the structured form, e.g. for MX:
'':
octodns:
cloudflare:
values:
- value:
preference: 10
exchange: mx1.example.com.
comment: "primary MX"
- value:
preference: 20
exchange: mx2.example.com.
comment: "backup MX"
ttl: 300
type: MX
values:
- preference: 10
exchange: mx1.example.com.
- preference: 20
exchange: mx2.example.com.A per-value entry whose value does not match any of the record's values is reported at plan time (raised under strict_supports, otherwise warned), as is a malformed values list. Cloudflare can hold two objects with the same value but different metadata, which can't be represented per-value; the first is kept and a warning is logged on dump, and the same limitation applies on apply — the provider matches Cloudflare objects by value, so duplicate objects can't be individually managed and one may be left untouched.
The TagAllowListFilter/TagRejectListFilter processors consider a record's per-value tags as well as its record-level tags — a record is treated as carrying a tag if any of its values do.
Note: A, AAAA, CNAME and ALIAS records support a Cloudflare Regional Services (Data Localization) region. The value is the Cloudflare region_key (e.g. eu, isoeu, us, ca, …).
This is opt-in: set regional_services: true on the provider to enable it. When disabled (the default), the provider never calls the regional services API — no behaviour change and no extra request for existing users. This matters because Regional Services is an Enterprise add-on and the API errors for accounts without the entitlement.
providers:
cloudflare:
class: octodns_cloudflare.CloudflareProvider
token: env/CLOUDFLARE_TOKEN
regional_services: truewww:
octodns:
cloudflare:
proxied: true
region: eu
ttl: 120
type: A
value: 1.2.3.4Constraints, because Cloudflare manages regions per-hostname on a separate API (/zones/{id}/addressing/regional_hostnames) rather than on the DNS record itself:
- A region applies to the whole hostname, so every proxiable record sharing a name (e.g. an
AandAAAAonwww) must declare the sameregion; conflicting values are reported viastrict_supports. - Regions only take effect on proxied records. A
regionon a non-proxied record is applied but inert until the record is proxied; it is reported viastrict_supports. - Regional Services is a Cloudflare Enterprise add-on and must be enabled on the account before any region can be set.
- The existing
DNS:Read/DNS:Edittoken permissions already cover the regional hostnames API — no additional scope is required. - Adoption: if a zone already has regional hostnames configured, add the matching
region:to your records before the first sync — otherwise octoDNS sees no region in your config and removes the existing regional hostnames.octodns-dump(withregional_services: true) emits the currentregionvalues to start from.
CloudflareProvider supports A, AAAA, ALIAS, CAA, CNAME, DS, LOC, MX, NAPTR, NS, PTR, SPF, SRV, SSHFP, TXT, and URLFWD. There are restrictions on CAA tag support.
CloudflareProvider does not supports root NS record management. They can partially be managed in the API, errors are thrown if you include the Cloudflare name servers in the values, but the system completely ignores the values set and serves up its own regardless.
CloudflareProvider does not support dynamic records.
Required Permissions for API Token are Zone:Read, DNS:Read, and DNS:Edit.
Page Rules:Edit is also required for managing Page Rules (URLFWD) records, otherwise an authentication error will be raised.
Important Note: When using a CloudFlare token you should NOT provide an email address or you will receive an error.
An example when using Page Rules (URLFWD) records -
Cloudflare has a different minimum TTL for enterprise and non-enterprise zones. See the documentation for more information. In the past the CloudflareProvider had a fixed minimum TTL set to 120 seconds and for backwards compatibility this is the current default.
| Processor | Description |
|---|---|
| ProxyCNAME | Allows Cloudflare proxied records to be used on other providers without exposing the proxied record value. Points other providers to the relevant .cdn.cloudflare.net subdomain. Useful to allow split authority with a secondary provider while still retaining Cloudflare benefits for certain records. |
| TagAllowListFilter | Filter that ONLY manages records with the specified tags, all others will be ignored. Useful for grouping records across zones (e.g. by team, department) so that they can be managed independently. |
| TagRejectListFilter | Filter that IGNORES records with the specified tags, all others will be managed. Useful for filtering out specific records that are that are managed externally (e.g. through Terraform). |
| TtlToProxy | Ensure Cloudflare's proxy status is setup depending on the TTL set for the record. This can be helpful for octodns_bind.ZoneFileSource or the like. |
See the /script/ directory for some tools to help with the development process. They generally follow the Script to rule them all pattern. Most useful is ./script/bootstrap which will create a venv and install both the runtime and development related requirements. It will also hook up a pre-commit hook that covers most of what's run by CI.