Why caddy 2 is not able to serve static brotli files?

If i follow your logic i can just use it like that:

localhost {
    root * "/Users/imax/PhpstormProjects/globus/web"
    encode gzip zstd
    php_fastcgi 127.0.0.1:9000
    @brotli {
        file {path}.br
    }
    handle @brotli {
        header Content-Encoding br
        rewrite * {http.matchers.file.relative}.br
    }
    try_files {path} /index.php?p={path}&{query} /index.php?{query}

    file_server
}

But it doesn’t work, it sets brotli encoding for html files which clearly don’t exist

Here i have .br files for .css files but i don’t ahve for .js files.
It doesn’t detect it properly, i have no idea how to make it work.

When i try to debug and do this:

localhost {
    root * "/Users/imax/PhpstormProjects/globus/web"
    encode gzip zstd
    php_fastcgi 127.0.0.1:9000
    @brotli {
        file {path}.br
    }
    handle @brotli {
        respond "{file} {http.matchers.file.relative}.br"
        #header Content-Encoding br
        #rewrite @brotli {http.matchers.file.relative}.br
    }
    try_files {path} /index.php?p={path}&{query} /index.php?{query}

    file_server
}

{file} and {http.matchers.file.relative} are both already set to index.php

You are right, it’s not wrong, it’s confusing… especially for people who used it in caddy1

Sorry, it should be:

@brotli {
    file {
        try_files {path}.br
    }
}

I am on my way to sleep so I didn’t test it for you. (I would like the first syntax I gave you to work though, so I’ll submit a PR for that in the morning.)

It doesn’t work, now it’s okay for not-br-precompiled links but for https://localhost/assets/styles/blue/sections/globus.css for example (has .br file nearby) it is decoding failed.

My caddyfile:

localhost {
    root * "/Users/imax/PhpstormProjects/globus/web"
    encode gzip zstd
    php_fastcgi 127.0.0.1:9000
    @brotli {
        file {
            try_files {path}.br
        }
    }
    handle @brotli {
        #respond "{file} {http.matchers.file.relative}.br"
        header Content-Encoding br
        rewrite @brotli {http.matchers.file.relative}.br
    }
    try_files {path} /index.php?p={path}&{query} /index.php?{query}

    file_server
}

Aye. Unlearning convention Caddy 1 invented is a pain point we see all over the place. Ultimately it’s important to remember that Caddy v1 and v2 are, essentially, completely different programs. There’s an absolutely massive amount of feature parity, but they’re just not the same underneath the hood at all.

Implementing automatic precompressed asset serving in Caddy v2 could be a good issue. Currently the closest one that mentions this is v2: Content negotiation · Issue #2665 · caddyserver/caddy · GitHub, but it’s not explicitly for this feature, only some functionality that would make this feature easier.

I actually figured it out, the solution is:

localhost {
    root * "/Users/imax/PhpstormProjects/globus/web"
    encode gzip zstd
    php_fastcgi 127.0.0.1:9000
    @brotli {
        file {
            try_files {path}.br
        }
    }
    handle @brotli {
        header Content-Encoding br
        rewrite * {http.matchers.file.relative}
    }
    try_files {path} /index.php?p={path}&{query} /index.php?{query}

    file_server
}

Thank you everyone

3 Likes

D’oh, you’re right. I added an extra .br to the end of my rewrite. I need some sleep. :sleeping:

Thanks for following up with the solution! Maybe we should make a wiki page here explaining it.

Edit: The file matcher syntax (for most common use cases) will become one-liner soon: file_server: Accept files args in one-liner of Caddyfile matcher by mholt · Pull Request #3298 · caddyserver/caddy · GitHub

2 Likes

Okay i got one more problem. After i enable this brotli thing all my svg images stop loading and displaying in img tag. I believe it’s related to mime types.

Do all these SVG images have a Brotli sidecar as well?

Content-Type could be an issue. We are only strictly overriding the Content-Encoding in the config, but the issue could be showing up at the file server.

Does that issue (image not loading) also happen for PNG, JPEG etc. files with a Brotli sidecar?

It doesn’t happen because it doesn’t make sense to encode PNG and JPEG with brotli, but svg is basically text. I only use brotli for static text files.

Ah, now I remember why content negotiation is tricky: the Content-Type header is based on file extension, so adding .br to the extension breaks the lookup in the MIME tables.

1 Like

Yup, any solution?

I’m thinking.

It may not be ready before 2.0, but if not it can come after.

Edit: So, yes, there is a solution, but it’s a bit verbose; you can always set the Content-Type header yourself, but it’ll be different for each different kind of file you serve. Still, if it’s a pretty standard static site, there won’t be more than ~5-10 types.

How can i do it? Now i only use brotli for css, js and svg

header gets executed before handle and rewrite, so theoretically we can easily manually re-specify the Content-Type based on the request without even messing with the existing Brotli sidecar detection/rewrite. The file server should leave the manually-set Content-Type header alone, I think?

Try something like this.

@brotli {
  file {
    try_files {path}.br
  }
}
handle @brotli {
  header Content-Encoding br
  rewrite {http.matchers.file.relative}
}

@svg {
  file
  path *.svg
}
header @svg Content-Type image/svg+xml

@css {
  file
  path *.css
}
header @css Content-Type text/css

@js {
  file
  path *.js
}
header @js Content-Type text/javascript

If you wanted to be fast and dirty but risk setting the wrong Content-Type on a 404, you could skip all of the matcher declarations and just go with:

@brotli {
  file {
    try_files {path}.br
  }
}
handle @brotli {
  header Content-Encoding br
  rewrite {http.matchers.file.relative}
}

header *.svg Content-Type image/svg+xml
header *.css Content-Type text/css
header *.js  Content-Type text/javascript
1 Like

@Whitestrake Except, path matchers have to start with / if they’re inlined, i.e. header *.svg ... won’t work.

(I wonder if we should change that. But it’d presume that no first arguments would really start with *.)

That’s a good point! The quick and dirty version would have to be:

header /*.svg Content-Type image/svg+xml
header /*.css Content-Type text/css
header /*.js  Content-Type text/javascript

Should work, right?

Actually, wait, would that only match by single path element? Like they’d match /foo.svg but not /foo/bar.svg?

Maybe it just does have to be the long version. Oh well, it is a bit more accurate that way.

Correct, it’d have to be the named matcher (“long way” :slight_smile: ) – since * in the middle of a path are like globular matches.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.

For whoever finds this in the future, this is now possible since v2.4.0, using the file_server directive’s precompressed option.

3 Likes