Setting header for specific extensions

Hello everyone.

I have a rather simple question even though it might seem obvious for most. I am currently trying to set the correct cache control headers for a gatsby website I’m deploying. The rules are pretty straightforward:
Nothing should be cached besides CSS, JS and /static/ files. Currently I’m trying to do it like this:

my.site {
    root * /path/to/site/

    route {
        header Cache-Control "public, max-age=0, must-revalidate"
        header /static/* Cache-Control "public, max-age=31536000, immutable"
        header *.css Cache-Control "public, max-age=31536000, immutable"
        header *.js Cache-Control "public, max-age=31536000, immutable"
    }

    try_files {path}.html {path}
    file_server
    encode gzip
}

This works fine for /static/ and for the rest of the site but it does ignore the *.js and *.css part, which makes sense now that I’ve read a bit more about request matchers and the doc about the header directive, but I can’t seem to figure out the proper way to achieve this.

If anyone could give me some pointers, that would be great.

Caddy 2.3.0, Debian w/ systemd

Please upgrade to v2.4.6! That’s an old version!

See the syntax docs for request matchers. Inline path matchers must start with a / otherwise they aren’t considered to be a matcher.

For path matchers that don’t start with / then you need to use a named matcher.

The reason you didn’t get a config error is because header directive allows for 3 arguments, in which case the first argument would be the header name, the second would be a search string for the header value, and the third would be the replacement.

Will do! My ansible playbook should do that automatically but for some reason it doesn’t.

Oh okay! I guess I missed that line in the documentation. So replacing *.js with /*.js should do the trick if I understand correctly? I just tried and it seems to work fine.

Ha that’s why the config seemed to work fine.

Thanks a lot for your detailed answer!

That’ll work if the .js file is at the top level, but * as a glob in the middle of the path matcher will not cross / boundaries. So /app.js will match, but /js/app.js won’t.

Instead you should use a named matcher to make a path matcher that uses a suffix match. Like this:

@js path *.js
header @js Cache-Control "public, max-age=31536000, immutable"
2 Likes

Amazing! Thanks for the tip, I didn’t realize it would only work for top level.

1 Like