Skip to content

DNS Provider Configuration

fuomag9 edited this page Sep 26, 2026 · 8 revisions

DNS Provider Configuration

Get wildcard certificates and validate domains without opening ports 80/443 using DNS-01 challenges.

Table of Contents

  1. What DNS-01 Does
  2. Supported Providers
  3. Configuration in Settings
  4. Provider Setup Guides
  5. Per-Certificate Provider Override
  6. Using Wildcard Certificates
  7. Migrating from Cloudflare-Only Settings
  8. Credential Storage
  9. Troubleshooting

What DNS-01 Does

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:

  1. Caddy asks Let's Encrypt for a certificate
  2. Let's Encrypt gives a challenge token
  3. Caddy uses the configured DNS provider's API to create a TXT record
  4. Let's Encrypt checks the DNS record
  5. Certificate issued, DNS record cleaned up

Supported Providers

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.


Configuration in Settings

Step 1: Navigate to DNS Providers

  1. Log in to Caddy Proxy Manager
  2. Click Settings in the menu
  3. Select the DNS Providers tab

Step 2: Add a Provider

  1. Select a provider from the dropdown
  2. Fill in the required credential fields
  3. Click Save

You can configure multiple providers simultaneously. One is set as the default and used for all new certificates unless overridden.

Step 3: Set a Default Provider

If you have multiple providers configured, select which one should be the default for ACME DNS-01 challenges.

Challenge Propagation Settings (optional)

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.


Provider Setup Guides

Cloudflare

  1. Log in to Cloudflare Dashboard
  2. Profile → API Tokens → Create Token
  3. Use the "Edit zone DNS" template or create a custom token with Zone → DNS → Edit
  4. Scope to your specific zone or "All zones"
  5. 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

Amazon Route 53

  1. Create an IAM user or role with route53:ChangeResourceRecordSets and route53:ListHostedZonesByName
  2. Generate access keys
  3. Fill in Access Key ID, Secret Access Key, and Region
  4. 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.

DigitalOcean

  1. Go to API → Tokens → Generate New Token
  2. Grant read and write permissions
  3. Copy the token into CPM

Duck DNS

  1. Log in to Duck DNS
  2. Copy your token from the homepage
  3. Paste into CPM

Hetzner

  1. Go to Hetzner DNS Console → API Tokens
  2. Create a token
  3. Paste into CPM

Vultr

  1. Go to Vultr Account → API
  2. Copy your API Key
  3. Paste into CPM

Porkbun

  1. Go to Porkbun Account → API Access
  2. Create API Key and Secret Key
  3. Enter both in CPM

GoDaddy

  1. Go to GoDaddy Developer Portal
  2. Create a production API key
  3. Enter as key:secret in the API Key:Secret field

Namecheap

  1. Go to Namecheap API Access
  2. Enable API access and whitelist your server IP
  3. Enter your API Key and Username in CPM

OVH

  1. Create API credentials at OVH API
  2. Grant GET/PUT/POST/DELETE /domain/zone/* permissions
  3. Enter Endpoint (e.g. ovh-eu), Application Key, Application Secret, and Consumer Key

IONOS

  1. Go to IONOS Developer Portal
  2. Create an API token
  3. Enter the token in prefix.secret format

Linode (Akamai)

  1. Go to Linode Cloud Manager → API Tokens
  2. Create a Personal Access Token with Domains read/write
  3. Paste into CPM

Spaceship

  1. Log in to Spaceship and open Launchpad → API Manager
  2. Generate an API key/secret pair
  3. Enter the API Key and API Secret in CPM

netcup

  1. Log in to the netcup CCP
  2. Open Webspace → API (or Starter → API depending on product) and enable the Webspace API
  3. Note your customer number, and generate an API key and API password
  4. Enter all three in CPM

netcup's DNS propagation is slow, so CPM defaults the DNS challenge to a 600s propagation delay and a 900s propagation timeout for netcup. You can override both in the provider's Propagation Delay / Propagation Timeout fields (see Challenge Propagation Settings).

deSEC

  1. Log in to deSEC and create an account
  2. Generate a token under Token Management
  3. Paste the token into CPM

Dynu

  1. Log in to Dynu and open Control Panel → API Credentials
  2. Create an API token (OAuth2)
  3. Paste the token into CPM

acme-dns

  1. Register an account on your acme-dns instance, e.g. curl -X POST https://auth.acme-dns.io/register
  2. Note the returned username, password, subdomain, and fulldomain
  3. Create a CNAME record from _acme-challenge.example.com to the acme-dns fulldomain
  4. 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.

Infomaniak

  1. Log in to Infomaniak Manager
  2. Go to the DNS zone → API settings and create an API token with domain management scope
  3. Paste the token into CPM

ClouDNS

  1. Log in to the ClouDNS control panel
  2. Open API & Resellers and create an API user (or an API sub-user for restricted access)
  3. Set the API password and note the API user ID (Auth ID) or sub-user ID
  4. If you restrict the API user by allowed IP addresses, whitelist the host Caddy runs on
  5. 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.

RFC2136 (BIND / TSIG)

  1. 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
  2. Add a key clause for the generated key and grant it update permission on the zone(s) in named.conf:
    key "transfer-key" {
      algorithm hmac-sha256;
      secret "cWnu6Ju9zOki4f7Q+da2KKGo0KOXbCf6Pej6hW3geC4=";
    };
    
    zone "example.com" {
      type master;
      file "example.com.zone";
      allow-update { key "transfer-key"; };
    };
    
  3. Reload/reconfigure BIND after editing named.conf
  4. 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. The key_alg must match the algorithm of the TSIG key exactly (e.g. hmac-sha256).


Per-Certificate Provider Override

By default, all certificates use the default DNS provider configured in Settings. You can override this per proxy host:

  1. Edit or create a proxy host
  2. In the certificate settings, select a different DNS provider from the dropdown
  3. Save

This is useful when different domains are managed by different DNS providers.


Using Wildcard Certificates

Creating Wildcard Proxy Host

  1. Click Proxy Hosts → Add Proxy Host
  2. Set domain to *.example.com (note the asterisk)
  3. Set your upstream
  4. Save

Caddy will automatically request the wildcard certificate via DNS-01 using your configured provider.

What Wildcard Covers

*.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)

Migrating from Cloudflare-Only Settings

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).


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 cloudflare setting. The web container logs Encrypted N DNS provider credential(s) that were stored in plaintext. Nothing has to be re-entered.
  • To change SESSION_SECRET, put the old value in SESSION_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's SESSION_SECRET (see Feature Guide Instance Sync).

Troubleshooting

DNS Challenge Failed

Error: DNS challenge failed or TXT record not found

Solutions:

  1. Verify your credentials are correct for the selected provider
  2. Increase Propagation Delay / Propagation Timeout for the provider (see Challenge Propagation Settings) — especially for netcup, ClouDNS, or other providers with slow zone replication
  3. Check DNS propagation: dig _acme-challenge.example.com TXT
  4. Check Caddy logs:
    docker compose logs caddy | grep -i dns
  5. Wait 1-5 minutes for DNS propagation (varies by provider)

Permission Denied

Error: Permission denied or Insufficient permissions

Solutions:

  1. Verify the API token has write permissions for DNS records
  2. Check that the token is scoped to the correct zone/domain
  3. Recreate the token with the correct permissions

Wildcard Certificate Not Working

Symptom: Individual certs work, wildcard doesn't

Solutions:

  1. Confirm a DNS provider is configured in Settings → DNS Providers
  2. Check domain format: use *.example.com not example.com/*
  3. DNS-01 is required for wildcards — HTTP-01 cannot obtain wildcard certs
  4. Check logs:
    docker compose logs caddy | grep -i wildcard

Rate Limit Exceeded

Error: Provider API rate limit exceeded

Solutions:

  1. Wait for the rate limit window to expire (varies by provider)
  2. Use wildcard certs instead of individual certs to reduce API calls
  3. For Cloudflare: add Zone ID to reduce lookups

Related Documentation


Need help? Open an issue with error details (never share API tokens!).

Clone this wiki locally