Skip to content

Instantly share code, notes, and snippets.

@sabrina-zeidan
Last active January 9, 2023 19:43
Show Gist options
  • Save sabrina-zeidan/08b8ab1cc6a57be2fa895222d3fb5fe5 to your computer and use it in GitHub Desktop.
Save sabrina-zeidan/08b8ab1cc6a57be2fa895222d3fb5fe5 to your computer and use it in GitHub Desktop.
Serve WebP without plugin straight from the server
upstream php {
{{#each fastcgi_servers}}
server {{this}};
{{/each}}
}
# SZ START
# Check if client is capable of handling webp
map $http_accept $webp_suffix {
default "";
"~*webp" ".webp";
}
# SZ END
server {
listen {{port}};
root "{{root}}";
index index.php index.html index.htm;
#
# Generic restrictions for things like PHP files in uploads
#
include includes/restrictions.conf;
#
# Gzip rules
#
include includes/gzip.conf;
#
# WordPress Rules
#
# SZ START
# Serve WebP straight from the server. Not in the browsers as plugins do. Your WebPs should be already there. This is to SERVE WebP in compatible browsers, not create
# instead of png, jpg and jpeg formats
location ~* ^(/wp-content/.+)\.(png|jpe?g)$ {
set $base $1.$2; # Capture image path and file extension
set $webp_uri $base$webp_suffix; # URI of the WebP version (filename.jpeg.webp)
set $webp_old_uri $base.$2$webp_suffix; # "URI of the original file
set $root "C:\Users\Sabrina\Local Sites\start\app\public"; # path to the /wp-content from server
root $root;
add_header Vary Accept;
if ( !-f $root$webp_uri ) { # Check if WebP version exists
add_header WebP_404 $root$webp_uri; # if there is no WebP version -- just add a header WebP_404 with the value of the path where WebP file was requested from -- for debugging
}
try_files $webp_uri $webp_old_uri $uri =404; # redirect to WebP version if all is good
}
# Possible improvement: To compare size of the WebP version and original before serving WebP
# Mind that the benefit of WebP is not only the size, but also -- that browsers are able to decode this format quicker, so this makes sense only in case WebP version is significantly larger than original
# Better possible improvement: set up webp generation on server; check filesize after webp is created, compare to original, if significantly larger ( > 30-40%) -- delete WebP, create a file to indicate it was deleted for a reason and shouldn't be recreated again
# To generate WebP automatically on server it's convenient to use Lua for that (install through OpenResty releases https://github.com/openresty/lua-nginx-module#installation)
# How-to in detail #https://requestmetrics.com/web-performance/nginx-image-optimization
# Filesize with Lua https://gist.github.com/maugre/4d0da857ceaac48d4e0c
# SZ END
{{#unless site.multiSite}}
include includes/wordpress-single.conf;
{{else}}
include includes/wordpress-multi.conf;
{{/unless}}
#
# Forward 404's to WordPress
#
error_page 404 = @wperror;
location @wperror {
rewrite ^/(.*)$ /index.php?q=$1 last;
}
#
# Static file rules
#
location ~* \.(?:css|js)$ {
access_log off;
log_not_found off;
add_header Cache-Control "no-cache, public, must-revalidate, proxy-revalidate";
}
location ~* \.(?:jpg|jpeg|gif|png|ico|xml)$ {
access_log off;
log_not_found off;
expires 5m;
add_header Cache-Control "public";
}
location ~* \.(?:eot|woff|woff2|ttf|svg|otf) {
access_log off;
log_not_found off;
expires 5m;
add_header Cache-Control "public";
# allow CORS requests
add_header Access-Control-Allow-Origin *;
}
#
# PHP-FPM
#
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;
fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $host;
fastcgi_param HTTPS $fastcgi_https;
fastcgi_param REDIRECT_STATUS 200;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass php;
fastcgi_buffer_size 64k;
fastcgi_buffers 32 32k;
fastcgi_read_timeout 1200s;
proxy_buffer_size 64k;
proxy_buffers 32 32k;
proxy_busy_buffers_size 256k;
}
}
# In case hosting doesn't let you edit conf files or allows with very limited functionality. Well, that sucks.
# WPEngine allows clients to add a few bits of nginx conf, but not map directive (first bit of the code above where we check if client's browser supports WebP.
# So here is what can be done (this is how WebP Express does it, and anyone else can too):
# Contact their support and ask them to add the following lines to Before-In-Location field in their system for the specific site
# You might also ask them to remember to reloaded the server configuration and purge caches (I had to do so to get it work)
location ~* ^/wp-content/.*\.(png|jpe?g|svg)$ {
add_header Vary Accept;
expires 365d;
}
location ~* ^/wp-content/.*\.webp$ {
expires 365d;
if ($whattodo = AB) {
add_header Vary Accept;
}
}
if ($http_accept ~* "webp"){
set $whattodo A;
}
if (-f $request_filename.webp) {
set $whattodo "${whattodo}B";
}
if ($whattodo = AB) {
rewrite ^(.*) $1.webp last;
}
if ($whattodo = A) { # if there is no WebP version -- do what -- ideally, generate WebP on server side
}
@sabrina-zeidan
Copy link
Author

On WP Engine the rules should be added to the Before-In-Location field in their system

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