Ресайз изображений на лету с помощью Nginx

Иногда,  когда вы создаете какой то сайт, вам требуется отображать картинки разных размеров в разных местах. Для этого вам приходится делать какой то функционал который либо в фоне, либо при первом запросе, либо еще хуже, при загрузке создает картинку в нужном размере и показывает пользователю.

Если ваш сайт на PHP то вам необходимо ставить дополнительные библиотеки, например ImageMagic или GD, и создавать дополнительную нагрузку на PHP

Но есть более элегантное решение. Так как Nginx обычно отвечает за отдачу статики, то и менять размеры картинок можно поручить ему.

Для этого уже есть готовый модуль, давайте попробуем его настроить.

Для того что бы все завелось мне пришлось добавить новый репозиторий в список

echo 'deb http://nginx.org/packages/ubuntu/ jammy nginx' | sudo tee -a /etc/apt/sources.list

У меня версию Ubuntu jammy, вам нужно указать свою версию из доступных здесь

Узнать вашу версию можно так

lsb_release -c

Дальше нужно добавить ключ к репозиторию

wget https://nginx.org/keys/nginx_signing.key 
sudo apt-key add nginx_signing.key

Ну и дальше, обновляем информацию о репозиториях  и устанавливаем плагин

sudo apt-get update
sudo apt-get install nginx-module-image-filter

Настройка

Когда все установлено, нужно подключить плагин и настроить правила ресайза.

Редактируем конфиг

sudo vim /etc/nginx/nginx.conf

И добавляем, где нибудь в самом верху, загрузку плагина

load_module modules/ngx_http_image_filter_module.so;
Например так
worker_processes auto;
load_module modules/ngx_http_image_filter_module.so;

error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;

events {
worker_connections 1024;
}

http {

Проверяем что все работает
sudo nginx -t
Если ошибок нет, то идем настраивать дальше. Если есть, то читаем что за ошибки, и идем гуглить или спрашивать в комментариях.

Ниже сильно упрощенный вариант конфигурационого файла /etc/nginx/sites-enabled/example.ru

server{
    listen 80;
    root /var/www/;
    index index.php;
    server_name example.ru;

    location / {
        rewrite ^/(.*)/$ /$1 permanent;
        try_files $uri $uri/ /index.php?$query_string;
    }

    #image resize for location example /resize/200x300/user/avatar.jpg
    location ~* ^/resize/(?<width>[\d-]+)x(?<height>[\d-]+)/(?<image>.*)$ {
        expires max;
        add_header X-my-header $image;
        # Proxy to internal image resizing server.
        proxy_pass http://127.0.0.1:81/$image?width=$width&height=$height;
        proxy_cache images_cache;
        proxy_cache_valid 200 500h;
    }
}

proxy_cache_path /tmp/nginx-image-cache levels=1:2 keys_zone=images_cache:10m inactive=500h max_size=1000m;
limit_req_zone $binary_remote_addr zone=30persec:32k rate=30r/s;
server {
    # Internal image resizing server.
    listen 81;
    allow 127.0.0.1;
    deny all;
    limit_req zone=30persec burst=60;

    location / {
        alias /var/www/upload/;
        image_filter resize $arg_width $arg_height;
        image_filter_jpeg_quality 85;
        image_filter_buffer 10M;
        error_page 404 = /empty;
    }

    location = /empty {
        alias /var/www/upload/empty.png;
    }
}

То есть, мы описали еще один сервер который слушает порт 81, и перенаправляем туда весь трафик попадающий под паттерн нашего пути к картинке.
Если такой картинки нет, то отдаем заранее подготовленную пустую.
Так же здесь можно поиграться с качеством картинки, что способствует ускорению загрузки сайта.

Проверяем что правило работает нормально

sudo nginx -t

И обновляем конфигурацию

sudo /etc/init.d/nginx reload

теперь при запросе картинки /var/www/upload/avatar.jpg вы можете получать эту картинку разного размера следующими способави

— example.ru/resize/200×300/avatar.jpg
— example.ru/resize/200x-/avatar.jpg
— example.ru/resize/-x300/avatar.jpg

Надеюсь материал был полезен. Если что то не работает, задавайте вопросы в комментариях.