caddyserver/caddy · error

DNS challenge enabled, but no DNS provider configured

Error message

DNS challenge enabled, but no DNS provider configured

What it means

Returned by ACMEIssuer.Provision (modules/caddytls/acmeissuer.go:216) when the DNS-01 challenge is enabled but no provider could be found: neither a locally configured provider module (dns directive on the issuer) nor a global dns app referenced by the TLS app. Caddy refuses to create a DNS-01 solver without a provider because it could never clean up or propagate records.

Source

Thrown at modules/caddytls/acmeissuer.go:216

	if iss.Challenges != nil && iss.Challenges.DNS != nil && iss.Challenges.DNS.solver == nil {
		var prov certmagic.DNSProvider
		if iss.Challenges.DNS.ProviderRaw != nil {
			// a challenge provider has been locally configured - use it
			val, err := ctx.LoadModule(iss.Challenges.DNS, "ProviderRaw")
			if err != nil {
				return fmt.Errorf("loading DNS provider module: %v", err)
			}
			prov = val.(certmagic.DNSProvider)
		} else if tlsAppIface, err := ctx.AppIfConfigured("tls"); err == nil {
			// no locally configured DNS challenge provider, but if there is
			// a global DNS module configured with the TLS app, use that
			tlsApp := tlsAppIface.(*TLS)
			if tlsApp.dns != nil {
				prov = tlsApp.dns.(certmagic.DNSProvider)
			}
		}
		if prov == nil {
			return fmt.Errorf("DNS challenge enabled, but no DNS provider configured")
		}
		iss.Challenges.DNS.solver = &certmagic.DNS01Solver{
			DNSManager: certmagic.DNSManager{
				DNSProvider:        prov,
				TTL:                time.Duration(iss.Challenges.DNS.TTL),
				PropagationDelay:   time.Duration(iss.Challenges.DNS.PropagationDelay),
				PropagationTimeout: time.Duration(iss.Challenges.DNS.PropagationTimeout),
				Resolvers:          iss.Challenges.DNS.Resolvers,
				OverrideDomain:     iss.Challenges.DNS.OverrideDomain,
				Logger:             iss.logger.Named("dns_manager"),
			},
		}
	}

	// add any custom CAs to trust store
	if len(iss.TrustedRootsPEMFiles) > 0 {
		iss.rootPool = x509.NewCertPool()
		for _, pemFile := range iss.TrustedRootsPEMFiles {

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Add a DNS provider to the issuer: tls { dns cloudflare {env.CF_API_TOKEN} } (requires the plugin build)
  2. Or configure the global dns app and reference it: apps { dns { provider ... } } so all issuers share it
  3. If you did not intend DNS-01, remove the empty challenges.dns block or the wildcard hostname that forces it
  4. Build the binary with the needed plugin via xcaddy if the module is missing

Example fix

# before: wildcard forces DNS-01, no provider
 *.example.com {
   tls {
     # nothing here
   }
 }

# after
 *.example.com {
   tls {
     dns cloudflare {env.CF_API_TOKEN}
   }
 }
Defensive patterns

Strategy: validation

Validate before calling

# config-time guard: any wildcard hostname or dns challenge block needs a provider
# CI check (simplified):
#   config contains 'dns' challenge or '*.' hostname  =>  config must contain
#   a 'dns <provider>' directive or a global 'dns' app block
grep -q '^\s*\*\.' Caddyfile && ! grep -qE '^\s*dns (cloudflare|route53|desec|\w+)' Caddyfile && {
  echo "wildcard cert requires a DNS provider"; exit 1; }

Try / catch

if err := issuer.Provision(ctx); err != nil {
    if strings.Contains(err.Error(), "DNS challenge enabled, but no DNS provider") {
        // add 'dns <provider> <creds>' to the issuer or a global dns app; or drop the wildcard
    }
    return err
}

Prevention

When it happens

Trigger: Enabling the DNS challenge implicitly (e.g. requesting a wildcard certificate forces DNS-01) without any dns provider configured; or via JSON where challenges.dns is a non-null object (e.g. only propagation_timeout set) with no provider_raw and no global dns app - merely enabling the dns challenge block triggers this error.

Common situations: Wildcard certs (*.example.com) requested with no DNS plugin installed; global dns app configured in a different config snippet that was not imported; JSON configs with "challenges": {"dns": {}} as an empty object after removing provider settings during cleanup.

Related errors


AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15). Data as JSON: /api/errors/da2cb40c51b611a3. Report an issue: GitHub.