Example for per file headers (abstract: using rewrite + proxy to get more done)

Trying around with per file headers and various other things, I finally got a solution using rewrite and proxy:

localhost:1313 {
  # cache headers for static files
  rewrite {
    if_op or
    if {path} has /images/
    if {path} has /css/
    if {path} has /fonts/
    if {path} has /icons/
    to /x-cache-header/{uri}
  }
  proxy /x-cache-header/ {
    without /x-cache-header
    upstream localhost:1314
    transparent
    header_downstream Cache-Control "max-age=172800"
    header_downstream -Server ""
  }
  # resource hint + cache header for index
  rewrite {
    if {path} is "/"
    to /x-index-header/{uri}
  }
  proxy /x-index-header/ {
    without /x-index-header
    upstream localhost:1314
    transparent
    header_downstream Cache-Control "no-cache, max-age=86400"
    header_downstream +Link "<https://stats.example.com>; rel=preconnect"
    header_downstream +Link "</css/main.css>; rel=preload"
    header_downstream +Link "</images/bg.jpg>; rel=preload"
    header_downstream +Link "</css/images/overlay.png>; rel=preload"
    header_downstream -Server ""
  }
}
localhost:1314 {
}

This gives us the possibility to set headers using regexp, paths etc…

Furthermore this can be used to enable various plugins on a per file, basis. For example cors or minify could be done on one file only instead of on a whole path.

3 Likes

Wait, how did this work as expected? The line if_op should return an error if you do not specify the operator. :flushed:
It should one of if_op and or if_op or.

rewrite / {
    if_op
    if {path} has /images/
    if {path} has /css/
    if {path} has /fonts/
    if {path} has /icons/
    to /x-cache-header/{uri}
}

By the way, good to hear you finally got it to work.

Yeah you are right, I copied an old version. I edited it to reflect the running version.

It was not only ‘if_op or’, which was needed, but also (which is quite unintuative) ‘-Server “”’. Without the empty string at the end it can’t parse the caddyfile.

It panicked? O.o That’s weird…

Wrong choice of words. It fails parsing. It has a different syntax as the header plugin. The header plugin doesn’t need an empty string.

Cool, thanks for posting how you got it to work! Clever trick.

@abiosoft as you are the expert for rewrite. Any new ideas how one could eliminate the proxy overhead? Would love to simplify the caddyfile.

If you have any hints, I might have some time to check it out again on my own.

Thanks so far.

Looks like the main thing you want to do is to manipulate headers. Right ?

Yeah setting headers using either the path or the file types or a mixture. I didn’t get it to work with rewrite.

The preload headers should be on the index of /, and all caching headers should be on all static assets either using the path or the file type.

Hope that makes sense.

That will require adding if conditions support to header. If there’s enough votes for this, I’ll do that.

Using rewrite alone wouldn’t be sufficient? Not sure, if it makes sense that we are adding if support to various middlewares, when we already have a specific rewrite middleware, which should be leveraged in my opinion. What would the reasoning be for duplicating the if code/functionality within header? Easier caddyfiles? Less overhead?

Using rewrite alone won’t be sufficient except rewrite have the ability to manipulate headers.

The challenge from the snippet below is to serve the file after rewrite has rewritten the path to /x-index-header.

rewrite {
  if {path} is /
  to /x-index-header/{uri}
}

We don’t have to force a simpler solution as long as we can savely recommend the proxy hacky solution.

Thanks again for taking the time and bearing with me :wink: