Skip to content

Instantly share code, notes, and snippets.

@Apkawa
Last active November 8, 2019 11:00
Show Gist options
  • Save Apkawa/1deada27a09481747fa6a8b9343901a0 to your computer and use it in GitHub Desktop.
Save Apkawa/1deada27a09481747fa6a8b9343901a0 to your computer and use it in GitHub Desktop.
Nginx resize with invalidation after change source image
function etag_resize (r) {
function done (r2) {
// Extract etag header
var source_etag = r2.headersOut.etag
// Pass variables from location
var width = r.variables.width
var height = r.variables.height
var image_path = r.variables.image_path
var convert_path = r.variables.convert_path || '/_ei/'
// construct resize with cache url
var path = `${convert_path}${image_path}?width=${width}&height=${height}&source_etag=${source_etag}`
r.internalRedirect(path)
}
r.subrequest(r.variables.image_path, { method: 'HEAD' }, done)
}
# We need njs and image_filter module. Also avaiable on docker image `nginx:1.17`
load_module /etc/nginx/modules/ngx_http_image_filter_module.so;
load_module /etc/nginx/modules/ngx_http_js_module.so;
http {
# .. other setting default
proxy_cache_path /nginx-data/resize/ levels=1:2 keys_zone=resize_images:512m inactive=30d max_size=10G;
# Important!
js_include etag_resize.js;
server {
listen 80;
server_name _;
location /media {
# Etag must be enabled!
etag on;
alias /public/media/;
# TODO cache
expires 1y;
# access_log off;
add_header Vary Accept-Encoding;
add_header Cache-Control public;
}
location ~* '^/i/(\d+)x(\d+)/(.*)$' {
# https://example.org/i/<width>x<height>/path/to/image.png
set $width $1;
set $height $2;
set $image_path /$3;
js_content etag_resize;
}
location ~* '^/i/w(\d+)/(.*)$' {
# https://example.org/i/w<width>/path/to/image.png
set $width $1;
set $height "-";
set $image_path /$2;
js_content etag_resize;
}
location ~* '^/i/h(\d+)/(.*)$' {
# https://example.org/i/w<width>/path/to/image.png
set $width "-";
set $height $1;
set $image_path /$2;
js_content etag_resize;
}
location ~* '^/i/(.*)$' {
# https://example.org/i/path/to/image.png
set $width 100;
set $height 100;
set $image_path /$1;
js_content etag_resize;
}
location /_ei/ {
# Based by https://gist.github.com/phpdude/1451684
# Magic from
# https://stackoverflow.com/questions/28684300/nginx-pass-proxy-subdirectory-without-url-decoding/37584637
rewrite ^ $request_uri;
rewrite ^/_ei/(.*) $1 break;
# End magic
root /nginx-data/resize/;
set $width $arg_width;
set $height $arg_height;
set $source_etag $arg_source_etag;
if ($source_etag ~* '^"(.*)"$') {
set $source_etag $1;
}
if ($uri ~* "^/_ei/(.*)" ) {
set $image_path $1;
}
if ($image_path ~* "^.*\.(.*)$") {
set $ext $1;
}
set $image_uri __resize/$image_path?width=$width&height=$height;
set $resize_status 'no';
set $image_store_path "$image_path/$source_etag/${width}x${height}.$ext";
set $abs_image_store_path "/nginx-data/resize$image_store_path";
if (!-f $abs_image_store_path) {
proxy_pass http://127.0.0.1:80/$image_uri;
set $resize_status 'yes';
break;
}
proxy_store $abs_image_store_path;
proxy_store_access user:rw group:rw all:r;
proxy_temp_path /tmp/images;
# For debug
add_header X-Filename $abs_image_store_path;
add_header X-Resize-Status $resize_status;
add_header X-Source-Etag $source_tag;
expires 1y;
access_log off;
add_header Vary Accept-Encoding;
add_header Cache-Control public;
rewrite ^(.*)$ $image_store_path break;
}
location /__resize/ {
alias /public/;
image_filter_buffer 50M;
image_filter resize $arg_width $arg_height;
image_filter_jpeg_quality 75;
allow 127.0.0.0/8;
deny all;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment