Caddy's built-in `tls.get_certificate.http` module fetches a certificate from an HTTP backend on every TLS handshake, with no caching. To avoid hammering their app backend for certificates that rarely change, the author built `caddy-get-certificate-cache` — an open-source Caddy module (Apache-2.0) that wraps the same HTTP fetch in an in-process cache. Key features include: honoring `Cache-Control: s-maxage` from the backend, configurable `ttl` and `negative_ttl`, optional disk persistence via `cache_dir` for warm restarts, singleflight coalescing of concurrent cache misses, and context isolation so a disconnecting client doesn't cancel in-flight fetches. HTTP 200 responses are cached, HTTP 204 (no cert for domain) is cached as a negative entry, and errors are not cached so transient failures self-heal. The module is available on GitHub and listed on Caddy's official module directory, installable via `xcaddy`.

5m read timeFrom ma.ttias.be
Post cover image
Table of contents
The setup #get_certificate runs on every handshake #The module #Gotchas #Get it #

Questions this post answers

Does Caddy cache the result of get_certificate HTTP lookups between TLS handshakes?

No, Caddy does not cache get_certificate results between handshakes. The underlying certmagic library calls the certificate manager on every TLS handshake by design — there is an open issue tracking this (caddyserver/caddy#7038). For a getter that reads from disk this is fine, but for an HTTP getter it means a backend round trip on every connection. Engineers running Caddy with custom certificate backends track issues like this on daily.dev before they hit production.

How do I add caching to Caddy's tls.get_certificate.http module?

Use the `caddy-get-certificate-cache` module (module ID `tls.get_certificate.cached_http`), a drop-in replacement for the stock `http` getter. Replace `http` with `cached_http` in your Caddyfile and configure `ttl`, `negative_ttl`, and optionally `cache_dir` for disk persistence. It honours `Cache-Control: s-maxage` from the backend, coalesces concurrent cache misses via singleflight, and is built with `xcaddy build --with github.com/ohdearapp/caddy-get-certificate-cache`. Teams building multi-tenant TLS setups with Caddy share patterns like this on daily.dev.

What happens when multiple concurrent TLS handshakes miss the certificate cache at the same time in caddy-get-certificate-cache?

Concurrent cache misses for the same SNI are coalesced into a single upstream request using Go's singleflight package. A burst of handshakes for a cold domain triggers exactly one backend fetch, not one per handshake. Additionally, the fetch runs with its own 10-second timeout rather than inheriting the triggering handshake's context, so a disconnecting client does not cancel the fetch and leave other waiting handshakes stranded. Caddy module design decisions like this are worth following on daily.dev when you are building high-traffic TLS infrastructure.