Open-Source Wikis

/

Caddy

/

How to contribute

/

Debugging

caddyserver/caddy

Debugging

Caddy is not chatty by default. When something doesn't behave, you usually need to do one of three things: turn up the log level, see exactly what config is running, or attach a profiler.

Crank up logging

Add a logging block to the Caddyfile (or set Config.Logging in JSON):

{
    debug
}

That sets the default logger to DEBUG. For per-module verbosity:

{
    log default {
        level DEBUG
    }
    log accesslog {
        include http.log.access
        output file /var/log/caddy/access.log
    }
}

Implementation: logging.go builds the zap logger tree at provision time. Per-module loggers come from caddy.Context.Logger() (context.go), which returns a child logger named after the module's ID — so a debug line about the file server has fields tying it back to http.handlers.file_server.

See the actual JSON

If you suspect the Caddyfile adapter is doing something surprising:

caddy adapt --config Caddyfile --pretty

adapt exits without starting any servers. Useful flags:

  • --validate — also run the provisioning step and abort on errors.
  • --adapter caddyfile (default if config ends in Caddyfile).

Inspect the live config

While Caddy is running:

curl localhost:2019/config/                          # full config
curl localhost:2019/config/apps/http/servers/srv0/   # subtree
curl localhost:2019/pki/ca/local                     # local CA info
curl localhost:2019/reverse_proxy/upstreams           # health of upstreams
curl localhost:2019/metrics                           # Prometheus

Routes are registered in admin.go and by modules implementing caddy.AdminRouter (modules/caddyhttp/reverseproxy/admin.go, modules/caddypki/adminapi.go, modules/metrics/).

Common failure modes

Symptom What to check
loading config: provisioning module 'http': loading http app … Look at the chain of nested errors — Caddy reports the full path through the module tree. The leaf error is the real one.
address … already in use on reload Another Caddy is running, or a previous instance didn't release sockets. listen_unix.go uses SO_REUSEPORT to allow graceful handoff but only across the same process group.
Reload silently restored the old config The new config returned an error during Provision/Validate/Start. Caddy's Load runs Cleanup and rolls back without crashing. Check the log; the error will be there even if the CLI looks happy.
tls: failed to load certificates caddytls couldn't reach storage or the issuer. Inspect ~/.local/share/caddy (Linux), ~/Library/Application Support/Caddy (macOS), or %AppData%\Caddy (Windows).
ACME challenges fail in tests Use the dns.providers.mock provider; see caddytest/integration/mockdns_test.go.

Profiling

The admin endpoint also exposes Go's pprof handlers because admin.go imports net/http/pprof:

curl -o /tmp/cpu.prof "http://localhost:2019/debug/pprof/profile?seconds=30"
go tool pprof /tmp/cpu.prof

Available profiles include goroutine, heap, allocs, mutex, and block.

Getting a stack trace

Send SIGQUIT (Linux/macOS) for a full goroutine dump:

kill -QUIT $(pgrep caddy)

sigtrap_posix.go and sigtrap.go install handlers for SIGINT, SIGTERM, and SIGUSR1. SIGUSR1 triggers a graceful reload using the most recent config file.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Debugging – Caddy wiki | Factory