View Categories

Configure NGINX to transparently serve next-gen format files when supported

ShortPixel Image Optimizer (SPIO) has 2 native WebP/AVIF delivery methods, but sometimes neither is able to properly serve your next-gen format files, especially if you have an NGINX server (which does not support .htaccess files). If this is the case for you, and you have ShortPixel properly configured to generate (but not deliver) WebP or AVIF files, the best option is to use the capabilities of NGINX and transparently serve the WebP/AVIF version of your original file, if supported.

The solution is simple, albeit manual: edit the NGINX configuration files, either nginx.conf or, if you have a setup with multiple sites, the appropriate configuration file from /etc/nginx/sites-available.

Stop here! Before reading the instructions, make sure you understand the following:

  • This method does not work for websites with Cloudflare's free plan.
  • After everything is configured, your WebP or AVIF files will show up with the same URL and extension. Your browser will display image.jpg, but the image will actually be a WebP/AVIF file.
  • This solution is the version we have found to accomplish this task most successfully. If it does not work as expected or does not meet your requirements, we recommend you to get professional help from an NGINX expert. Hey, if you find something better, drop us a line too!
  • If you are using a CDN provider that is not Cloudflare, or if you have a paid plan from Cloudflare, you need to make sure it supports the Vary header and is properly configured to deliver WebP and AVIF from the same URL based on browser capabilities so that it knows (and caches and delivers accordingly) that there could be 3 different files to deliver for the same URL depending on the Accept header sent by the browser.
    • Examples: bunny.net / Cloudflare
    • If you are using a CDN that does not support the Vary header, or if you do not have the technical knowledge to implement it, you should not use this solution at all, or you may end up serving WebP/AVIF images to browsers that do not support them. Instead, use one of the alternative solutions described at the end of this article.

The instructions defer depending on what format(s) you want to deliver.

WebP and AVIF

These instructions are valid for when you have enabled the "Create WebP versions of the images" and "Create AVIF versions of the images" options, which means that you want to serve AVIF and WebP files (WebP will only be served when AVIF is not supported by the visitor's browser).

  1. Add the necessary AVIF MIME type in the NGINX configuration. For this, follow this guide.
  2. Insert this block before the server directive, which creates the $webp_suffix and $avif_suffix variables if the visitor's browser has WebP and/or AVIF capabilities:

map $http_accept $webp_suffix {

default "";

"~*webp" ".webp";

}

map $http_accept $avif_suffix {

default "";

"~*avif" ".avif";

}

  1. Insert this block inside the server directive:

location ~* ^(/wp-content/.+).(png|jpe?g)$ {

set $base $1;

set $double_extension $1.$2;

add_header Vary Accept;

try_files $double_extension$avif_suffix$webp_suffix $base$avif_suffix$webp_suffix $double_extension$avif_suffix $base$avif_suffix $double_extension$webp_suffix $base$webp_suffix $uri =404;

}

  1. Disable ShortPixel's native delivery method. Go to Settings > ShortPixel > Advanced and uncheck the box "Deliver the next generation versions of the images in the front-end":

Only WebP

These instructions are valid for when you have enabled only the "Create WebP versions of the images" option, which means that you want to serve WebP files (and not AVIF).

  1. Insert this block before the server directive, which creates the $webp_suffix if the browser supports WebP:

map $http_accept $webp_suffix {

default "";

"~*webp" ".webp";

}

  1. Insert this block inside the server directive:

location ~* ^(/wp-content/.+).(png|jpe?g)$ {

set $base $1;

set $webp_uri $base$webp_suffix;

set $webp_old_uri $base.$2$webp_suffix;

set $root "<<FULL PATH OF WP-CONTENT PARENT>>";

root $root;

add_header Vary Accept;

if ( !-f $root$webp_uri ) {

add_header X_WebP_SP_Miss $root$webp_uri;

}

try_files $webp_uri $webp_old_uri $uri =404;

}

  1. Make sure to replace <<FULL PATH OF WP-CONTENT PARENT>> with the actual absolute path to the wp-content folder, without the folder itself. Example: /home/john/public_html/. The  X_WebP_SP_Miss header is not necessary, but useful for testing – this header is set if the browser has WebP capabilities, but no WebP version of the image is found on disk. You can disable it later by commenting out the entire if directive.
  2. Disable ShortPixel's native delivery method. Go to Settings > ShortPixel > Advanced and uncheck the box "Deliver the next generation versions of the images in the front-end".

Only AVIF

These instructions are valid for when you have enabled only the "Create AVIF versions of the images" option, which means that you want to serve AVIF files (and not WebP).

  1. Add the necessary AVIF MIME type in the NGINX configuration. For this, follow this guide.
  2. Insert this block before the server directive, which creates the $avif_suffix if the browser has AVIF capability:

map $http_accept $avif_suffix {

default "";

"~*avif" ".avif";

}

  1. Insert this block inside the server directive:

location ~* ^(/wp-content/.+).(png|jpe?g)$ {

set $base $1;

set $avif_uri $base$avif_suffix;

set $avif_old_uri $base.$2$avif_suffix;

set $root "<<FULL PATH OF WP-CONTENT PARENT>>";

root $root;

add_header Vary Accept;

if ( !-f $root$avif_uri ) {

add_header X_AVIF_SP_Miss $root$avif_uri;

}

try_files $avif_uri $avif_old_uri $uri =404;

}

  1. Make sure to replace <<FULL PATH OF WP-CONTENT PARENT>> with the actual absolute path to the wp-content folder, without the folder itself. Example: /home/john/public_html/. The  X_AVIF_SP_Miss header is not necessary, but useful for testing – this header is set if the browser has AVIF capabilities, but no AVIF version of the image is found on disk. You can disable it later by commenting out the entire if directive.
  2. Disable ShortPixel's native delivery method. Go to Settings > ShortPixel > Advanced and uncheck the box "Deliver the next generation versions of the images in the front-end".

Example (Plesk)

Let us say you want to only deliver WebP files. If you use Plesk to manage your NGINX server, you can follow these instructions.

  1. Connect to the Plesk server via SSH.
  2. Create the /etc/nginx/conf.d/webp.conf file by entering the following command:

touch /etc/nginx/conf.d/webp.conf

  1. Open the webp.conf file in a text editor (e.g. vi editor) and add the following content:

map $http_accept $webp_suffix {

default "";

"~*webp" ".webp";

}

  1. Save the changes and close the file.
  2. Log in to Plesk and go to Domains > yourdomain.com > Hosting & DNS > Apache & nginx settings.

  3. Paste the following code snippet into the Additional nginx directives field. Don't forget to replace YOUR_DOMAIN with your actual domain name (without www or https://):

location ~* ^(/wp-content/.+).(png|jpe?g)$ {

set $base $1;

set $webp_uri $base$webp_suffix;

set $webp_old_uri $base.$2$webp_suffix;

set $root "/var/www/vhosts/YOUR_DOMAIN/httpdocs/";

root $root;

add_header Vary Accept;

if ( !-f $root$webp_uri ) {

add_header X_WebP_SP_Miss $root$webp_uri;

}

try_files $webp_uri $webp_old_uri $uri =404;

}

  1. Go back to your SSH connection and enter the following command to restart the nginx service and apply the changes:

service nginx restart

Example (RunCloud)

This guide was kindly provided to us by Gustavo, a dear customer of ShortPixel (thank you!). We assume that your server is running Ubuntu and your web app is running NGINX, and that you want to deliver both WebP and AVIF.

Important: Make sure that there is no expiration header cache rule set by NGINX that controls the expiration time of the files in question (jpg|jpeg|png|webp|avif). When this rule is enabled, the server returns only the original images (PNG or JPG) and not the optimized images (WebP or AVIF, as supported by the browser).

  1. Make sure that the required AVIF MIME types are present in the NGINX configuration. To do this, connect to your server and edit the /etc/nginx-rc/mime.types file.
  2. Make sure you see the following lines, and if not, add them:

image/avif avif;

image/avif-sequence avifs;

  1. Now go to /etc/nginx-rc/conf.d/ and once in it, create a configuration file there with the name of your choice (in this example it is images.conf).
  2. Edit the images.conf file and insert the following code:

map $http_accept $webp_suffix {

default "";

"~*webp" ".webp";

}

map $http_accept $avif_suffix {

default "";

"~*avif" ".avif";

}

  1. Log in to your RunCloud dashboard, select the web app of your choice and click on NGINX Config.

  2. Click on the button Add a New Config.
  3. On the new screen, select the following:
    1. Predefined Config: I want to write my own config
    2. Type: location.main-before
    3. Config Name: whatever you want, e.g. shortpixel
  4. Insert this block:

location ~* ^(/wp-content/.+).(png|jpe?g)$ {

set $base $1;

set $double_extension $1.$2;

add_header Vary Accept;

try_files $double_extension$avif_suffix$webp_suffix $base$avif_suffix$webp_suffix $double_extension$avif_suffix $base$avif_suffix $double_extension$webp_suffix $base$webp_suffix $uri =404;

}

  1. Save the new file and go to the main dashboard of your server in RunCloud. There go to Services > NGINX and click on Reload.

Alternatives

If you cannot use this method, you should try an alternative solution for WebP or AVIF image delivery: