Serve webp variant of png/jpg for supported clients

1. The problem I’m having:

I am looking for an efficient way to serve webp variants of jpgs and pngs to supported clients via Caddy. The webps have the same name as the original formats (https://example.com/image.webp and https://example.com/image.png).

The below directives seem to work fine for Apache and LiteSpeed, though I have no idea if they are efficient/optimized. A Caddyfile equivalent would be great if possible.

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{HTTP_ACCEPT} image/webp
    RewriteCond %{DOCUMENT_ROOT}/$1.webp -f
    RewriteRule (.+)\.(jpe?g|png)$ $1.webp [T=image/webp,E=accept:1]
</IfModule>

<IfModule mod_headers.c>
    Header append Vary Accept env=REDIRECT_accept
</IfModule>

AddType image/webp .webp

2. Error messages and/or full log output:

There is no error message. I asked three AIs to convert the code, and the outputs provided by all three are either invalid or don’t seem to work. From what I understand, the code they provided is looking for image.jpg.webp (or image.png.webp) instead of image.webp.

Response by Claude AI:

@images {
    path *.jpg *.jpeg *.png
}

handle @images {
    try_files {path}.webp {path}
    header Vary Accept
    header {path}.webp Content-Type image/webp
}

Another one by Claude AI (invalid syntax, ChatGPT had something similar):

@webp_available {
    file {
        try_files {path}.webp
    }
    header_regexp Accept image/webp
}

handle_path /*.jpg /*.jpeg /*.png {
    rewrite @webp_available {path}.webp
    header Vary Accept
}

header /*.webp Content-Type image/webp

Google Gemini:

http://localhost:80 {
    root /path/to/your/website

    file_server {
        root * {
            try_files {
                $uri.webp
                $uri
            }
        }
    }

    rewrite {
        if {
            path =~ ^(.+)\.(jpe?g|png)$
            header Accept contains image/webp
            file exists $1.webp
        } {
            path {
                $1.webp
            }
            header Accept {
                image/webp
            }
        }
    }
}

3. Caddy version:

2.8.4

4. How I installed and ran Caddy:

Caddy’s official deb repository

a. System environment:

Debian 12.6 amd64

b. Command:

n/a

c. Service/unit/compose file:

n/a

d. My complete Caddy config:

n/a

5. Links to relevant resources:

n/a

Your AI code conversions are superfluous, misinformed, and outright wrong. I can’t condemn them enough. Apart from lacking any kind of grasp of the actual issue you have, they’re spurting literal cargo-culted configuration that gives a false impression of what kind of configuration you should be focusing on. So they’re not useful for producing working config, and they’re not useful for giving you a guidepost as to what you should be trying to learn in order to produce a working config yourself. Throw out this AI-generated Caddyfile configuration entirely.

Instead, have a look at the examples in the documentation of try_files (Caddyfile directive) — Caddy Documentation; the last example gives us a very good clue as to how we might go about trying a rewrite to a different file extension:

Choose the most recently deployed version of a static file (e.g. serve index.be331df.html when index.html is requested):

try_files {file.base}.*.{file.ext} {
	policy most_recently_modified
}

Although the example isn’t aimed directly at you, the demonstration of file.base looks perfect for your use case. (The rest of the Caddyfile placeholders can be found at Caddyfile Concepts — Caddy Documentation).

Since file.base gives us the filename without the extension, we can reconstruct a path to a possible webp file with the request directory, the request file base, and a new extension.

So, let’s try that: try_files {dir}{file.base}.webp {path}

3 Likes

Thank you! The AI salad was driving me a little nuts. Your suggestion is much simpler and makes sense when I see it.

1 Like

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