Repository navigation
DNS Provider Configuration
Get wildcard certificates and validate domains without opening ports 80/443 using DNS-01 challenges.
- What DNS-01 Does
- Supported Providers
- Configuration in Settings
- Provider Setup Guides
- Per-Certificate Provider Override
- Using Wildcard Certificates
- Migrating from Cloudflare-Only Settings
- Credential Storage
- Troubleshooting
Proves you own a domain by creating DNS TXT records instead of serving files over HTTP. This means:
- You get wildcard certificates (
*.example.com) - Ports 80/443 don't need to be public
- Works for internal services
- No web server exposed during validation
The flow:
- Caddy asks Let's Encrypt for a certificate
- Let's Encrypt gives a challenge token
- Caddy uses the configured DNS provider's API to create a TXT record
- Let's Encrypt checks the DNS record
- Certificate issued, DNS record cleaned up
CPM supports 21 DNS providers via a pluggable registry. Credentials for password-type fields are encrypted at rest with AES-256-GCM (see Credential Storage).
| Provider | Fields | Notes |
|---|---|---|
| Cloudflare | api_token |
Zone:DNS:Edit permission |
| Amazon Route 53 |
access_key_id, secret_access_key, region, hosted_zone_id
|
Supports IAM roles (leave fields empty) |
| DigitalOcean | api_token |
|
| Duck DNS | api_token |
Dynamic DNS service |
| Hetzner | api_token |
|
| Vultr | api_token |
|
| Porkbun |
api_key, api_secret_key
|
|
| GoDaddy | api_token |
Format: key:secret
|
| Namecheap |
api_key, user
|
|
| OVH |
endpoint, application_key, application_secret, consumer_key
|
|
| IONOS | auth_api_token |
Format: prefix.secret
|
| Linode (Akamai) | api_token |
|
| Njalla | api_token |
|
| netcup |
customer_number, api_key, api_password
|
CCP API (Webspace → API) |
| Spaceship |
api_key, api_secret
|
|
| deSEC | token |
|
| Dynu | api_token |
|
| acme-dns |
username, password, subdomain, server_url
|
Delegated DNS-01 validation only |
| Infomaniak | api_token |
|
| ClouDNS |
auth_id or sub_auth_id, auth_password
|
API user or sub-user (API & Resellers) |
| RFC2136 (BIND / TSIG) |
key_name, key_alg, key, server
|
RFC 2136 dynamic updates via a TSIG key |
The provider list is also available via GET /api/v1/dns-providers.
- Log in to Caddy Proxy Manager
- Click Settings in the menu
- Select the DNS Providers tab
- Select a provider from the dropdown
- Fill in the required credential fields
- Click Save
You can configure multiple providers simultaneously. One is set as the default and used for all new certificates unless overridden.
If you have multiple providers configured, select which one should be the default for ACME DNS-01 challenges.
Every provider form also shows two optional tuning fields that control how long Caddy waits for the challenge TXT record to become visible before telling Let's Encrypt to verify it:
| Field | Meaning | Caddy default |
|---|---|---|
| Propagation Delay | How long to wait before starting the propagation checks (e.g. 60s, 5m) |
none |
| Propagation Timeout | Maximum time to wait for the TXT record to propagate (e.g. 2m, 15m). Use -1 to disable the propagation check entirely |
2m |
Accepts Caddy durations (30s, 10m, 1h30m, 2d, ...). Use these when certificate issuance fails with DNS challenge failed / TXT record not found even though the provider credentials work — typical for DNS providers that replicate zones slowly.
For example, to tune a slow provider, set Propagation Delay to 600s and Propagation Timeout to 900s. CPM generates:
"challenges": {
"dns": {
"provider": { "name": "...", "...": "credentials" },
"propagation_delay": "600s",
"propagation_timeout": "900s"
}
}netcup ships with these values as defaults (600s delay, 900s timeout) because of its notoriously slow DNS propagation; both can be overridden per provider. Custom resolvers for propagation checks can be configured under Settings → DNS Resolvers.
- Log in to Cloudflare Dashboard
- Profile → API Tokens → Create Token
- Use the "Edit zone DNS" template or create a custom token with Zone → DNS → Edit
- Scope to your specific zone or "All zones"
- Copy the token and paste it into the API Token field in CPM
Optional: Add your Zone ID (found on the domain Overview page) to reduce API calls.
Token format:
your-cloudflare-api-token
- Create an IAM user or role with
route53:ChangeResourceRecordSetsandroute53:ListHostedZonesByName - Generate access keys
- Fill in Access Key ID, Secret Access Key, and Region
- Optionally provide a Hosted Zone ID if you have multiple zones for the same domain
IAM role support: Leave all fields empty and use EC2 instance roles or environment-based credentials.
- Go to API → Tokens → Generate New Token
- Grant read and write permissions
- Copy the token into CPM
- Log in to Duck DNS
- Copy your token from the homepage
- Paste into CPM
- Go to Hetzner DNS Console → API Tokens
- Create a token
- Paste into CPM
- Go to Vultr Account → API
- Copy your API Key
- Paste into CPM
- Go to Porkbun Account → API Access
- Create API Key and Secret Key
- Enter both in CPM
- Go to GoDaddy Developer Portal
- Create a production API key
- Enter as
key:secretin the API Key:Secret field
- Go to Namecheap API Access
- Enable API access and whitelist your server IP
- Enter your API Key and Username in CPM
- Create API credentials at OVH API
- Grant
GET/PUT/POST/DELETE /domain/zone/*permissions - Enter Endpoint (e.g.
ovh-eu), Application Key, Application Secret, and Consumer Key
- Go to IONOS Developer Portal
- Create an API token
- Enter the token in
prefix.secretformat
- Go to Linode Cloud Manager → API Tokens
- Create a Personal Access Token with Domains read/write
- Paste into CPM
- Log in to Spaceship and open Launchpad → API Manager
- Generate an API key/secret pair
- Enter the API Key and API Secret in CPM
- Log in to the netcup CCP
- Open Webspace → API (or Starter → API depending on product) and enable the Webspace API
- Note your customer number, and generate an API key and API password
- Enter all three in CPM
netcup's DNS propagation is slow, so CPM defaults the DNS challenge to a
600spropagation delay and a900spropagation timeout for netcup. You can override both in the provider's Propagation Delay / Propagation Timeout fields (see Challenge Propagation Settings).
- Log in to deSEC and create an account
- Generate a token under Token Management
- Paste the token into CPM
- Log in to Dynu and open Control Panel → API Credentials
- Create an API token (OAuth2)
- Paste the token into CPM
- Register an account on your acme-dns instance, e.g.
curl -X POST https://auth.acme-dns.io/register - Note the returned
username,password,subdomain, andfulldomain - Create a CNAME record from
_acme-challenge.example.comto the acme-dnsfulldomain - Enter the username, password, subdomain, and server URL in CPM
acme-dns only serves ACME challenge records. The CNAME delegation must exist for every domain validated through it.
- Log in to Infomaniak Manager
- Go to the DNS zone → API settings and create an API token with domain management scope
- Paste the token into CPM
- Log in to the ClouDNS control panel
- Open API & Resellers and create an API user (or an API sub-user for restricted access)
- Set the API password and note the API user ID (Auth ID) or sub-user ID
- If you restrict the API user by allowed IP addresses, whitelist the host Caddy runs on
- Enter either the Auth ID or the Sub-user ID, plus the API password, in CPM
Exactly one of Auth ID / Sub-user ID is required, together with the API password. Make sure the API user is allowed to manage the zones Caddy serves.
- On your BIND9 (or compatible) DNS server, generate a TSIG key if you don't already have one, e.g.
tsig-keygen -a hmac-sha256 transfer-key - Add a
keyclause for the generated key and grant itupdatepermission on the zone(s) innamed.conf:key "transfer-key" { algorithm hmac-sha256; secret "cWnu6Ju9zOki4f7Q+da2KKGo0KOXbCf6Pej6hW3geC4="; }; zone "example.com" { type master; file "example.com.zone"; allow-update { key "transfer-key"; }; }; - Reload/reconfigure BIND after editing
named.conf - Enter the TSIG key name, algorithm, the base64-encoded secret, and the authoritative DNS server address (host:port) in CPM
The DNS server must accept RFC 2136 dynamic updates (
allow-update) for the zones Caddy manages. Thekey_algmust match the algorithm of the TSIG key exactly (e.g.hmac-sha256).
By default, all certificates use the default DNS provider configured in Settings. You can override this per proxy host:
- Edit or create a proxy host
- In the certificate settings, select a different DNS provider from the dropdown
- Save
This is useful when different domains are managed by different DNS providers.
- Click Proxy Hosts → Add Proxy Host
- Set domain to
*.example.com(note the asterisk) - Set your upstream
- Save
Caddy will automatically request the wildcard certificate via DNS-01 using your configured provider.
*.example.com covers:
-
app.example.com✓ -
api.example.com✓ -
anything.example.com✓
Does NOT cover:
-
example.com(root domain — create a separate proxy host) -
sub.app.example.com(nested subdomains)
If you previously used the legacy Cloudflare-only settings (Settings → Cloudflare tab), your configuration is automatically migrated to the new multi-provider format. No manual action is required. The Cloudflare credentials appear as a provider entry in Settings → DNS Providers.
The migration copies the API token as it was stored. Since v1.13.1, a token left in plaintext by the migration, and the one in the legacy cloudflare setting itself, are encrypted on the next start (see Credential Storage).
Password-type credential fields (API tokens, secrets, passwords) are stored encrypted with AES-256-GCM, using a key derived from SESSION_SECRET. GET /api/v1/settings/dns-provider never returns them; it only lists which fields are set (configuredFields).
Since v1.13.1:
- Providers saved through the REST API (
PUT /api/v1/settings/dns-provider) are stored encrypted, as the dashboard stores them. Older releases stored credentials saved this way in plaintext. - The legacy Cloudflare token is encrypted when it is saved (
PUT /api/v1/settings/cloudflare). - On startup, credentials still stored in plaintext are encrypted: providers saved through the REST API by an older release, the Cloudflare token copied by the migration above, and the legacy
cloudflaresetting. The web container logsEncrypted N DNS provider credential(s) that were stored in plaintext. Nothing has to be re-entered. - To change
SESSION_SECRET, put the old value inSESSION_SECRET_PREVIOUS; stored credentials are re-encrypted with the new secret on the next start (see Security Configuration#secret-rotation). A credential that no key decrypts has to be re-entered; see Troubleshooting#secret-decryption-issues. - With instance sync, a master on this release seals provider credentials to each upgraded slave's sync key, and the slave stores them encrypted with its own
SESSION_SECRET. A slave on v1.12.0 or earlier, or any slave of a master on v1.12.0 or earlier, still receives them encrypted with the master'sSESSION_SECRET(see Feature Guide Instance Sync).
Error: DNS challenge failed or TXT record not found
Solutions:
- Verify your credentials are correct for the selected provider
- Increase Propagation Delay / Propagation Timeout for the provider (see Challenge Propagation Settings) — especially for netcup, ClouDNS, or other providers with slow zone replication
- Check DNS propagation:
dig _acme-challenge.example.com TXT - Check Caddy logs:
docker compose logs caddy | grep -i dns - Wait 1-5 minutes for DNS propagation (varies by provider)
Error: Permission denied or Insufficient permissions
Solutions:
- Verify the API token has write permissions for DNS records
- Check that the token is scoped to the correct zone/domain
- Recreate the token with the correct permissions
Symptom: Individual certs work, wildcard doesn't
Solutions:
- Confirm a DNS provider is configured in Settings → DNS Providers
- Check domain format: use
*.example.comnotexample.com/* - DNS-01 is required for wildcards — HTTP-01 cannot obtain wildcard certs
- Check logs:
docker compose logs caddy | grep -i wildcard
Error: Provider API rate limit exceeded
Solutions:
- Wait for the rate limit window to expire (varies by provider)
- Use wildcard certs instead of individual certs to reduce API calls
- For Cloudflare: add Zone ID to reduce lookups
- Certificate Management - General certificate guide
- Environment Variables Reference - Configuration variables
- Security Configuration - Token security
- Feature Guide REST API - DNS providers API endpoint
- Troubleshooting - Common issues
Need help? Open an issue with error details (never share API tokens!).