caddyserver/caddy · critical
automate: managing %v: %v
Error message
automate: managing %v: %v
What it means
On TLS app Start(), all names registered via the 'automate' certificate loader (t.automateNames) are submitted to t.Manage for certificate issuance/renewal. If managing any of them fails — ACME challenges fail, issuers error, storage fails — Start aborts with this error, printing the whole automate name set.
Source
Thrown at modules/caddytls/tls.go:418
// Start activates the TLS module.
func (t *TLS) Start() error {
// warn if on-demand TLS is enabled but no restrictions are in place
if t.Automation.OnDemand == nil || (t.Automation.OnDemand.Ask == "" && t.Automation.OnDemand.permission == nil) {
for _, ap := range t.Automation.Policies {
if ap.OnDemand && ap.isWildcardOrDefault() {
if c := t.logger.Check(zapcore.WarnLevel, "YOUR SERVER MAY BE VULNERABLE TO ABUSE: on-demand TLS is enabled, but no protections are in place"); c != nil {
c.Write(zap.String("docs", "https://caddyserver.com/docs/automatic-https#on-demand-tls"))
}
break
}
}
}
// now that we are running, and all manual certificates have
// been loaded, time to load the automated/managed certificates
err := t.Manage(t.automateNames)
if err != nil {
return fmt.Errorf("automate: managing %v: %v", t.automateNames, err)
}
if t.EncryptedClientHello != nil {
echLogger := t.logger.Named("ech")
// publish ECH configs in the background; does not need to block
// server startup, as it could take a while; then keep keys rotated
go func() {
// publish immediately first
if err := t.publishECHConfigs(echLogger); err != nil {
echLogger.Error("publication(s) failed", zap.Error(err))
}
// then every so often, rotate and publish if needed
// (both of these functions only do something if needed)
for {
select {
case <-time.After(1 * time.Hour):View on GitHub (pinned to 50e54ee279)
Solutions
- Read the wrapped per-name error — it distinguishes challenge failure, rate limit, storage, and DNS issues
- Ensure ports 80/443 are publicly reachable, or configure the dns challenge with a working dns provider
- Set an ACME email and use the Let's Encrypt staging CA ('acme_ca') while debugging to avoid rate limits
- For local/internal names, attach an explicit policy with the internal issuer instead of relying on automate defaults
Example fix
# before: public ACME for an internal-only name
{"certificates": {"automate": ["myservice.lan"]}}
# after
{"automation": {"policies": [{"subjects": ["myservice.lan"], "issuers": [{"module": "internal"}]}]}} Defensive patterns
Strategy: retry
Validate before calling
# pre-flight: can a public CA reach us? nc -z -w3 yourhost 80 && nc -z -w3 yourhost 443 || echo 'challenge ports unreachable' dig +short yourhost A | grep -q . || echo 'no DNS record'
Try / catch
err := caddy.Start(cfg)
if err != nil && strings.Contains(err.Error(), "automate: managing") {
log.Printf("cert management failed: %v", err)
// server did not start; fix reachability/credentials and retry after backoff
} Prevention
- Ensure ports 80/443 are open and DNS points at the server before first start
- Use the staging ACME CA while testing bulk issuance
- Prefer explicit internal-issuer policies for non-public names
When it happens
Trigger: automate: ["example.com"] where port 80/443 are unreachable so HTTP/TLS-ALPN challenges fail; no ACME account email; DNS challenge provider misconfigured; firewall blocking Let's Encrypt validation; internal names without a qualifying policy. The wrapped error from certmagic contains per-name detail.
Common situations: First-run issuance on firewalled or NAT'd servers; rate limits from repeated test issuance; DNS not yet pointing at the server; clock skew breaking ACME; storage permission errors.
Related errors
- finalizing automatic HTTPS: %v
- provisioning default public automation policy: %v
- automate: manage %v: %v
- %s app module: start: %v
- starting caddy administration endpoint: %v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/cfe860a88a2d4737.
Report an issue: GitHub.