This file serves cat.webp for cat.jpg to browsers that accept WebP, under the same URL, and the original when no twin exists. It needs mod_rewrite, mod_headers and mod_mime, AllowOverride FileInfo and FollowSymLinks.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_ACCEPT} image/webp [NV]
RewriteCond %{REQUEST_FILENAME} ^(.+)\.(?:jpe?g|png)$ [NC]
RewriteCond %1.webp -f
RewriteRule ^(.+)\.(?:jpe?g|png)$ $1.webp [NC,END]
</IfModule>
AddType image/webp .webp
<IfModule mod_headers.c>
<FilesMatch "\.(?i:jpe?g|png|webp)$">
Header append Vary Accept
</FilesMatch>
</IfModule>Lines 1, 7, 9, 13. <IfModule> keeps originals flowing if a module is missing.
Line 2. Each .htaccess with rules needs its own RewriteEngine On (Merging and Inheritance).
Line 3. Only WebP-capable browsers pass; [NV] leaves Vary to line 11.
Line 4. The path minus its extension becomes %1, in any letter case.
Line 5. The twin must exist, so a missing WebP never becomes a 404.
Line 6. cat.jpg becomes cat.webp; END spares pass two (L vs END).
Line 8. Redundant on Ubuntu 225 , whose /etc/mime.types knows WebP, but portable.
Lines 10 to 12. Vary: Accept on every image makes a CDN keep one copy per format.
$ for f in cat.jpg dog.png; do for a in 'image/avif,image/webp,*/*' 'image/*'; do
> printf '%-8s %-26s ' $f "$a"; curl -so /dev/null -H "Accept: $a" \
> -w '%{content_type} %{size_download} %header{vary}\n' localhost:8105/images/$f; done; done
cat.jpg image/avif,image/webp,*/* image/webp 3100 Accept
cat.jpg image/* image/jpeg 5000 Accept
dog.png image/avif,image/webp,*/* image/png 4000 Accept
dog.png image/* image/png 4000 AcceptOne URL gave 3,100 bytes of WebP or 5,000 of JPEG, each with Vary: Accept; dog.png, with no twin, stayed a PNG.