Skip to content

Instantly share code, notes, and snippets.

@seeekr
Last active March 10, 2024 22:34
Show Gist options
  • Save seeekr/2415528 to your computer and use it in GitHub Desktop.
Save seeekr/2415528 to your computer and use it in GitHub Desktop.
enabling apache to serve WebP image files if accepted by browser (and .webp files available)
## !! This snippet has been updated, but not tested in practice. It should work, please check / leave comments in case it doesn't. !! ##
# originally from https://groups.google.com/a/webmproject.org/group/webp-discuss/browse_thread/thread/196ac4ea705688d8
<IfModule mod_rewrite.c>
# TODO: don't forget to put
# AddType image/webp .webp
# in your mods-available/mime.conf
# (though this is optional because we're setting
# the mime type manually in the RewriteRule)
# Enable rewrite
RewriteEngine On
# Does browser support WebP?
RewriteCond %{HTTP_ACCEPT} \bimage/webp\b
# Capture image name
RewriteCond %{REQUEST_URI} (.*)\.(jpe?g|png)$
# if you don't have all jpg/png images available
# as webp then you want to uncomment the next line
# so apache first checks if there is a webp file
# otherwise leave it disabled as it removes the
# need to query the disk
#RewriteCond %{DOCUMENT_ROOT}%1.webp -f
# Route to WebP image
RewriteRule .* %1\.webp [L,T=image/webp]
<IfModule mod_headers.c>
<FilesMatch "\.(jpe?g|png)$">
Header append Vary Accept
</FilesMatch>
</IfModule>
</IfModule>
@seeekr
Copy link
Author

seeekr commented Apr 18, 2012

thinking the redirect should be a permanent one... would the browser then not send another request to the original jpg/png image when it encounters that url once again and ask for the webp version immediately / get that one from cache immediately? will have to check that.
for pages with lots of images this redirect version would not be acceptable if that were not the case. if caching works regardless, then this would be fine.

@villelahdenvuo
Copy link

For some reason my Apache added an extra dot, so I had to remove "." from the RewriteRule to make it work. (If someone is having problems getting it to work.)

@psa-jforestier
Copy link

You should add some rules to add "Vary Accept" if Apache served the webp format, or the image could be cached on proxy or CDN in an incorrect format.

@mzealey
Copy link

mzealey commented Oct 3, 2017

RewriteCond %{REQUEST_URI}  (.*)(\.jpe?g|png)$ 

is wrong as @tuhoojabotti noticed - pngs wont work like that. should be:

RewriteCond %{REQUEST_URI}  (.*)(\.(jpe?g|png))$ 

@cantoute
Copy link

cantoute commented Oct 11, 2019

Perhaps this is what you need...

# as lacking in /etc/mime.types of many distributions (debian)
# without it won't work, but probably better off adding it there
AddType image/webp .webp

<IfModule mod_rewrite.c>
  RewriteEngine On

  RewriteCond %{HTTP_ACCEPT} image/webp
  RewriteCond %{REQUEST_FILENAME} -f
  RewriteCond %{REQUEST_FILENAME}.webp -f
  RewriteRule ^/?(.+?)\.(jpe?g|png)$ /$1.$2.webp [NC,T=image/webp,E=EXISTING:1,E=ADDVARY:1,L]

  <IfModule mod_headers.c>
    <FilesMatch "(?i)\.(jpe?g|png)$">
      Header append "Vary" "Accept"
    </FilesMatch>
  </IfModule>
</IfModule>

@seeekr
Copy link
Author

seeekr commented Oct 14, 2019

Thanks everyone for the comments.
@cantoute: Could you clarify why there are env variables set in the RewriteRule, and then not used anywhere? Is this taken from a snippet you're using in production?

@seeekr
Copy link
Author

seeekr commented Oct 14, 2019

I've incorporated the feedback, though I haven't actually tested it. Should still be a good enough starting point. Thanks all!

@cantoute
Copy link

cantoute commented Oct 15, 2019

Hi, sorry I didn't put any credits...

I was looking for this to enable webp on a single plain html page and landed here... I end up writing it... but tired of re-inventing the weal :-/

This is inspired by rules from wordpress plugin https://github.com/rosell-dk/webp-express (the guy has done an excellent job)

ADDVARY variable has a meaning and without it apache won't add the Vary header on a rewrite rule.

The other, I'm not sure... I know it works with it, but could have a meaning for apache as is could be for some other rules hook... in doubt I prefered keeping it.

I could not find documentation on ADDVARY magic variable, but I did test without it and Vary header goes missing too.
So when things magically work in what I consider as left overs from the 90s (fix one end brakes the other) I give up trying things.

This is based on heavily tested code... Wether one variable is needed over who knows what specific context, getting to that line took the dev of webp-express many many testing over many context... took him some effort.
I would just leave it untouched. As is it'll just work in the widest range of context encountered so far.

It ads the Vary header so it respects http standards...
This makes it compatible to use behind CDN...

Note: in case CDN ignored the Vary, one could add the 'Cache-Control: Private' which explicitly bans reverse proxy caching and still take advantage of browser cache.

Edit:
I did end up asking the question about the EXISTING variable... Best way to find out :)
rosell-dk/webp-express#380

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment