Operate Caddy

Observe requests and runtime

Separate access logs from runtime logs, preserve useful fields, and expose metrics only to an authorized monitoring path.

10 minute lesson

~~~

When something breaks, you need to know what Caddy saw. Caddy keeps two kinds of logs, and 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 enable per site with the log directive:

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

Now read the log. JSON logs are built for tooling, so use jq:

jq "{status: .status, uri: .request.uri, duration: .duration}" /var/log/caddy/app-access.log

Two entries, one 200 and one 404, each with URI and duration. Everything a request-debugging session needs, greppable and parseable. The file output rotates logs automatically, so this won’t silently fill the disk.

Here’s the division of labor between the two logs. 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. Status questions go to the access log; “why” questions go to journalctl -u caddy.

Caddy also exposes Prometheus metrics. 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

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.

One caution about log contents. Caddy redacts common credential headers like Authorization and Cookie by default — keep that protection. And remember that URLs themselves leak: a token in a query string lands in the access log in plain text. Treat log files with the same care as the data behind them.

Lesson completed

Take this course offline

Get every free book and course as PDF and EPUB files.

Get the download library →