HTTP caching mechanisms in Caddy

Providing the ability for clients to cache static file requests is very important. It prevents the unneeded transfer of (static) files from server to client. Caching doesn’t only speedup things for the client, but also decreases the server load.

But which caching mechanisms does Caddy provide, and how can they be enabled?


The HTTP ETag or entity tag is a header which contains an assigned identifier to each resource. The identifier is specific for each version of the resources. That way the client can do conditional requests by means of knowing whether a resource has changed or not.

What should we do to enable it in Caddy?
Well… you mustn’t do anything. ETag support is built-in and works out of the box (on static files) with Caddy! (It is included since version 0.8.3.) ❤️Caddy!


Another caching mechanism is the Cache-Control header field. This header field contains a value (in seconds) specifying how long the browser may cache a result (or whether it may even cache the request).

Caddy doesn’t have a directive for this, so I even started writing code for a middleware, which, after a few minutes of research, seemed completely useless, since we can easily add custom headers in the Caddyfile.

The Cache-Control values are fairly easy to understand and to use. For my WordPress blog I use these:

header /blog/wp-content/ Cache-Control "max-age=2592000"
header /blog/wp-includes/js/ Cache-Control "max-age=2592000"

Cache-Control is the name of the header field. max-age is the time interval (in seconds) for which the browser may cache the result. Other values of the Cache-Control header field:

  • public, max-age=2592000: responses may be cached by the client’s browser and all intermediary caches. The public directive is implicit so you don’t need to specify it.
  • private, max-age=2592000: responses may be cached by the client’s browser only
  • no-store: completely disable caching

Expires header

The expires header is outdated by the Cache-Control header. It contained the exact date on which the cache of a resource should expire. This value is thus set dynamically, which is something we can’t do with the header directive of Caddy.
But… In most modern systems the Cache-Control header is used instead of the expires header. So you can stick to the two above caching mechanisms.