Operate Caddy
Observe requests and runtime
Separate access logs from runtime logs, preserve useful fields, and expose metrics only to an authorized monitoring path.
When something breaks, you need to know what Caddy saw. Caddy keeps two kinds of logs. Knowing which one to read saves real time.
Access logs record HTTP requests: method, path, status, duration. Runtime logs record Caddy’s own operations: startup, reloads, certificate issuance, upstream errors.
Runtime logs are on by default. That’s what you’ve been reading in the journal. Access logs you turn on per site, with the log directive.
Enable access logs
Let’s log requests to a file, in JSON:
app.example.com {
log {
output file /var/log/caddy/app-access.log
format json
}
reverse_proxy 127.0.0.1:3000
}
Reload, then make one good request and one bad one:
curl -s https://app.example.com/ > /dev/null
curl -s https://app.example.com/nope > /dev/null
JSON logs are built for tools, not eyes, so read them with jq:
jq "{status: .status, uri: .request.uri, duration: .duration}" /var/log/caddy/app-access.log
You get two entries, one with status 200 and one with 404, each with its URI and duration. That’s everything a request-debugging session needs, and you can grep and filter it.
The file output rotates logs on its own, so this won’t fill the disk while you’re not looking.
Which log answers which question
Here’s the division of labor. A 502 shows up in the access log as the status the client received. The reason, connection refused, TLS failure, timeout, lives in the runtime log.
So status questions go to the access log. “Why” questions go to journalctl -u caddy. When I debug a proxy problem I keep both open side by side.
Metrics
Caddy also exposes Prometheus metrics, counters and histograms that a monitoring system scrapes on a schedule. Turn them on with the metrics global option:
{
metrics
}
Then scrape them from the admin endpoint:
curl -s http://localhost:2019/metrics | grep caddy_http_requests
You’ll see request counters broken down by server and status code.
That endpoint lives on the admin port, which never belongs on the public Internet. Point your monitoring at it over a private network or a tunnel, never through a public firewall rule.
Be careful with what you log
Caddy redacts common credential headers like Authorization and Cookie by default. Keep that protection on.
But remember that URLs leak too. A token in a query string lands in the access log in plain text, and no redaction rule saves you. Treat log files with the same care as the data behind them: same permissions, same retention, same access rules.
Lesson completed