Skip to content

Set up automatic DNS-01 (Cloudflare)

What you'll have at the end: the Hub holding a scoped Cloudflare API token that lets it publish and remove the _acme-challenge TXT records ACME DNS-01 validation needs, proven as far as the Hub's own health check goes.

Without a DNS provider the Hub cannot answer a DNS-01 challenge itself — a profile on the manual lane waits for you to publish the record by hand, and a profile on the automatic lane fails rather than degrading.

Configuration is proven here; a live Cloudflare renewal is not

The automatic DNS-01 lane as a whole works — it issued a real Let's Encrypt certificate on 2026-08-22 — but that run went through the AWS Route 53 adapter. Everything below the DNS provider (the propagation wait, the authoritative-nameserver check, the cleanup, the file bundle the Scout writes) is shared and is the proven part. What has not been exercised is Cloudflare's own record write and delete against a live ACME order — only its health check. Prefer Route 53 if you have the choice, and report what you see.

Prerequisites:

  • The zone for your domain is hosted on Cloudflare and is the one answering queries on the internet.
  • Permission to create an API token on that account.
  • Hub admin access.
  • Outbound HTTPS from the Hub to api.cloudflare.com, and outbound DNS on port 53 to internet nameservers — the propagation check queries your zone's authoritative servers directly. See Route 53 → Network the Hub needs, which is provider-independent.

1. Find your zone ID

Cloudflare dashboard → select the domain → Overview. The Zone ID is in the right-hand API panel: 32 hexadecimal characters. Copy it.

2. Create a scoped API token

My ProfileAPI TokensCreate TokenCreate Custom Token.

Setting Value
Permissions ZoneDNSEdit
Permissions ZoneZoneRead
Zone Resources Include → Specific zone → your domain

Both permissions are needed and neither is spare: the Hub reads the zone as its health check and edits DNS records to publish and withdraw challenges. Scoping to the one zone is what keeps the token from touching anything else.

⚠️ Use an API token, not the Global API Key. The global key carries your whole account and cannot be scoped; the Hub only ever needs these two permissions on one zone.

Create the token and copy it — Cloudflare shows it once.

3. Enter the credentials in the Hub

SettingsCertificate issuanceDNS providers → expand Add DNS provider.

Field Value
DNS provider ID A short name you choose, like corp-cloudflare. This is what a renewal profile stores; 1–64 characters of letters, digits, - or _, lowercased on save.
DNS provider name A display label
Service Cloudflare
API token from step 2
Zone ID from step 1

Use Show beside the token to check the paste before saving — a truncated token and a wrongly-scoped one fail the same way. The reveal shows what you have just typed, not anything the Hub has stored.

Click Save DNS provider. The token is stored AES-256-GCM encrypted under the CA passphrase and is write-only at the API surface.

One entry per zone, and entries do not replace each other. A Cloudflare credential holds exactly one zone ID, so a second zone is a second entry — and adding one does not disturb any Route 53 or Google Cloud DNS entry. The Hub stores as many as you add, and each renewal profile picks the one that serves its domains (step 5). Re-saving an existing DNS provider ID rotates that entry's credentials in place, without disturbing the profiles that name it.

If you see a 'Hub default (legacy)' block

Earlier releases stored a single Hub-wide DNS provider, and a Hub upgraded from one still holds it. It is what every renewal profile that has not chosen a provider of its own uses — so removing it stops DNS-01 for all of them.

4. Prove the credentials

Saving runs the health check — a token-authenticated read of the zone you named. It confirms the credentials or fails immediately, separating a credential problem from a certificate problem before any CA is involved. The check runs before the write, so a token Cloudflare rejects is never stored; the entry's Test button re-runs it later. A rejection is reported inside the DNS provider panel, beside the button.

Symptom Cause
Authentication error (10000) Token wrong, truncated, or revoked
Invalid request headers The Global API Key was pasted instead of a token
Zone not found Zone ID typo, or the token's Zone Resources do not include this zone
Permission denied Missing Zone:Read, or DNS:Edit was not granted

The health check only proves the Hub can read the zone. Zone:Read alone passes it; the missing DNS:Edit would only surface at the first renewal.

5. Point a renewal profile at it

SettingsRenewal Profiles → pick or create a profile → set Validation Method to DNS-01 (Automatic via API), then pick the entry from step 3 in the DNS Provider select that appears.

Only do this for domains inside the zone that entry names. The Hub writes _acme-challenge.<domain> into that one zone. For a wildcard the record is _acme-challenge.<apex> — the literal * label is not a legal DNS name.

⚠️ A profile that names a provider never falls back to another one. If the entry is removed, or its credentials will not decrypt, the renewal is refused rather than published through some other provider's zone.

⚠️ Automatic does not fall back to manual. With no provider configured at dispatch time the renewal fails with "acme_dns01_direct selected but no DNS provider is configured on this Hub".

What to watch for on the first live renewal

Because this adapter has not yet completed one, these are the places to look rather than a list of known symptoms:

  • The record write is a create, not an upsert. Route 53 UPSERTs, so a leftover record is simply overwritten; Cloudflare's adapter POSTs a new record. A stale _acme-challenge entry at the same name may cause Cloudflare to reject the create as a duplicate. Check the zone if a renewal fails at the publish step.
  • Cleanup is value-matched, deliberately: the Hub lists the TXT records at the challenge name and deletes only the one whose content equals its own value, so a concurrent order's record survives. That also means a record left behind by an older Hub is never swept — remove those by hand.
  • The propagation wait is 35 seconds, polled every 2 seconds against your zone's authoritative nameservers. If it times out, nothing was submitted to the CA and the order was not burned; retrying is safe.

The mechanics, and why each is the way it is, are documented once on the Route 53 page — everything there from step 3 onward is provider-independent.