Evaluates a group of directives mutually exclusively from other
handleblocks at the same level of nesting.The
handledirective is kind of similar to thelocationdirective from nginx config: the first matchinghandleblock will be evaluated. Handle blocks can be nested if needed. Only HTTP handler directives can be used inside handle blocks.
—handle (Caddyfile directive) — Caddy Documentation
So, at each level, only one handle directive is evaluated, and it’s the first one that matches.
I did note that when setting the same header like that multiple times, the generic one was always selected (header *), with no regard to either specificity or the order in which they’re set, so the longer-duration ones never seemed to apply.
Putting the longer-duration ones in a handle block while leaving the generic one on the top level seemed to fix that. This must be something to do with the fact they’re put in a subroute?
Wouldn’t mind @matt’s eyes and input on this one. At the very least, there should be some clear method of exercising control over which header is executed, so that cases of specific-over-general can be configured. Certainly, having to use handle groups in this manner to enable specificity of header directives isn’t ergonomic, nor is it particularly discoverable from documentation.
Anyway, I discovered through testing that the headers don’t need to be handled separately, they just need to be put in any subroute to “beat” the generic header. So here’s the neatest Caddyfile I could come up with that seems to work:
solovyov.net {
encode zstd gzip
header Cache-Control max-age=3600
handle /q/* {
uri strip_prefix /q
root * /mnt/share
file_server browse
}
handle {
header /static/* Cache-Control max-age=31536000
header /favicon.ico Cache-Control max-age=31536000
root * /opt/solovyov.net/www
file_server
}
}