2

I am trying to server webp images to supporting browsers by using the code below. I have already .webp images in addition to .png and .jpg images of the same file.

For example if have an image named vacation.jpg, i also have vacation.jpg.webp.

The code below works but it was overwriting my other location blocks before i switched to a CDN. Now i am using CDN that code block has no effect, no WEBP images in response and also not overwriting my other location blocks.

Here is how to do it:

Add to the /etc/nginx/mime.types

“image/webp webp”

Add to the main nginx.conf file:

map $http_accept $webp_suffix {
  default “”;
  “~*webp” “.webp”;
}

Add to the server block:

location ~* ^/wp-content/.+\.(png|jpg)$ {
  add_header Vary Accept;
  try_files $uri$webp_suffix $uri =404;
}

Restart or reload nginx.

Example of my other location blocks:

Disable Hot-Linking

location ~ .(ico|gif|png|jpe?g|svg|webp)$ {
    valid_referers none blocked example.com *.example.com;
    if ($invalid_referer) {
       return 403;
   }
}

Allow Cross-Origin For Static Domain Files

    location ~ \.(ico|gif|png|jpe?|svg|webp|eot|otf|ttf|ttc|woff|woff2|ogg|js|css|font.css)$ {
        add_header Access-Control-Allow-Origin "*";
        #gzip_vary on;
        expires 30d;
}
2

2 Answers 2

2

The original question was changed completely after I posted this answer and this answer is no longer relevant to the question.


Even though your intention is good, the fact that you do a 302 redirect when a .webp version is found, makes the gain smaller.

The redirect adds two round-trips in latency to picture loading time, and if the picture is small enough, it will take longer to receive the .webp version than the original.

To fix this, you should generate the URLs in your website code directly.

However, to answer your current question, you can use this set of rules:

location ~ ^(/wp-content.+)\.(jpe?g|png)$ {
    set $red Z;

    if ($http_accept ~* "webp") {
        set $red A;
    }

    if (-f $request_filename.webp) {
        set $red "${red}B";
    }

    if ($red = "AB") {
        add_header Vary Accept;
        return 302 $1.webp;
    }
}

The idea here is that one has already captured the first part of the filename in your location directive. Therefore the first part of the new location is in the $1 regex capture variable. So, one simply uses the $1 in the return directive. I use return here, since it is faster than rewrite.

3
  • Thanks for the explanation. How about the rewrite (.*) $1.webp redirect; ? And also some files don't have .webp version with the new plugin i use. (it doesn't create them if they will become larger than the current image) In the current code if i end up with the .webp extension only in the url. Is there a way to modify it so we can continue to server jpg or png when webp is not available? Oct 24, 2016 at 1:16
  • You can use the rewrite version too, it is just slower. For the other question, I don't think you cannot do that without nginx lua scripting. You should also have included that in your original question and not as a surprise question. However, the best way to address all these things is to fix your CMS so that it automatically generates proper URLs. Making a nginx config hack is not a good solution in the long run. Oct 24, 2016 at 9:32
  • I have changed the question and the code. Thanks for looking into this by the way. Let me ask you another question. Normally Wordpress images are like this: example.com/wp-content/uploads/2016/10/image.jpg. How can i rewrite it to make like example.com/image.jpg? Oct 24, 2016 at 23:13
0

After several years, the solutions to conditionally serving WebP images have not improved, and always requires some sort of http_accept that checks if the client browser supports it and then try_files to go and search if the files exist, and then finally serve the .webp file format.

If this sounds absolutely ridiculous, inefficient, and unstable, that's because it is.

This is not a direct answer, but it blows my mind that so many WordPress et al developers are pushing these solutions to the public, often with drastic negative consequences to SEO and website stability. In the blink of an eye these mapping solutions can result in thousands of 404 errors, 302 redirects, problems with vary and gzip especially if you are using e.g. Cloudflare or certain CDNs, and many other issues.

Just because Google is pushing their WebP format doesn't mean it's a good idea to go hacking your Nginx configuration to "maybe" get it working.

Remember, WebP is neither portable nor universal. It took forever for W3C to accept it as a standard, let alone non-Google companies (like Apple) to grudgingly begin to support it.

You can't edit WebP in e.g. Photoshop, or move it between your computer, your social media, your cloud storage, and your blog. It is a web-only optimized format that in my opinion should only exist in on-the-fly conversion apps at the edge (if at all). The average user, let alone web developer, has no business risking everything trying to stumble around these solutions.

We have thus far refused to support WebP mapping in our SlickStack (LEMP stack) project for exactly these reasons, and probably will continue to do so because of the instability and confusion it introduces.

If you really want to use WebP, enable on-the-fly conversion in your CDN, such as Cloudflare, and let their cutting-edge technology detect browsers and devices. Adding that load and responsibility to your origin server is a bad idea for so many reasons, just look at the overload of problems...

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .