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
- Add a DNS provider to the issuer: tls { dns cloudflare {env.CF_API_TOKEN} } (requires the plugin build)
- Or configure the global dns app and reference it: apps { dns { provider ... } } so all issuers share it
- If you did not intend DNS-01, remove the empty challenges.dns block or the wildcard hostname that forces it
- 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
- Associate every wildcard hostname in config review with a visible dns provider directive
- Never leave an empty challenges { dns { } } block in JSON configs - delete it instead
- Prefer configuring the provider once in the global dns app so all issuers inherit it
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
- expanding DNS override domain '%s': %v
- filling in global issuer defaults for AP %d, issuer %d: %v
- acme_dns specified without DNS provider config, but no provi
- filling in global issuer defaults for issuer %d: %v
- expanding email address '%s': %v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/da2cb40c51b611a3.
Report an issue: GitHub.