1. 1
  2. 2
  3. 3
  4. 4
  5. 5

# теория · шаг 3 из 5

Справочник: что ещё есть в стандартной сборке

Коротко

В стандартной сборке модулей вчетверо больше, чем прошёл курс, и половина решает задачу, ради которой обычно пишут код: другие протоколы до приложения (uwsgi, scgi, grpc, memcached), правка ответа на лету (sub_filter, ssi, addition, gunzip), файлы и картинки (dav, mp4, image_filter), разбор JSON прямо в конфиге (json_set) и целый третий корневой блок mail. Но «стандартная сборка» у каждого своя: часть модулей собирается только явно, и в официальном образе их нет.

Это карта, а не урок про одну мысль: читай оглавление, запоминай, что существует. Разборы про json_set и про содержимое официального образа стоит прочитать целиком.

Понадобилось уменьшать картинки на лету. Строка из документации, официальный образ nginx:alpine. Что скажет nginx -t?

/etc/nginx/conf.d/shop.local.confhttp server location /thumb/
image_filter resize 200 -;   # 200 - ширина, прочерк - «высоту подобрать по пропорции»
↳  выводnginx -t
nginx: [emerg] unknown directive "image_filter"

Модуль есть в документации, описан на сайте nginx, и его нет в твоём nginx. Список того, что документация называет стандартным, и список того, что собрано у тебя, - разные списки.

На что это похоже

Справочник по модулям - это аптечка, а не учебник. Наизусть дозировки никто не помнит; помнят, что в аптечке лежит жгут, и где он лежит. Половина времени, потраченного на «напишу-ка я для этого сервис», уходит зря именно потому, что человек не знал: жгут уже есть.

Поэтому читать этот урок надо один раз целиком, а возвращаться - по оглавлению.

Как это устроено: три состояния модуля

директива в конфиге вкомпилирован работает сразу динамический .so нужен load_module нет в сборке unknown directive nginx -V показывает первые два, третий виден только по ошибке
Строка в конфиге не заработает, пока модуля нет в сборке

Правило

Перед тем как писать директиву из документации, спроси свою сборку:

$  команда
nginx -V 2>&1 | tr ' ' '\n' | grep -E "with-|module"

Модули со звёздочкой в документации собираются только явно (--with-http_image_filter_module), в пакетах дистрибутивов часть вынесена в отдельные файлы (nginx-module-njs, nginx-module-image-filter), и тогда нужна строка load_module в самом верху конфига (.so - файл собранного модуля, load_module подключает его до всех блоков).

Разбор: что реально лежит в официальном образе

Прогон по образу nginx:alpine 1.31.5 - каждая директива проверена на unknown directive:

в сборке есть в сборке нет
ssi, sub_filter, addition, gunzip image_filter
uwsgi_pass, scgi_pass, grpc_pass, memcached_pass xslt_stylesheet
dav_methods, mp4, random_index, slice degradation
userid, charset, empty_gif, valid_referers perl_set
json_max_depth, stub_status, auth_request -

В debian-образе те же image_filter и xslt лежат отдельными файлами в /etc/nginx/modules/ - то есть там они есть, но молчат, пока не написан load_module. Один и тот же «официальный nginx» ведёт себя по-разному в двух официальных образах, и это стоит проверить до того, как под фичу заведена задача.

Разбор: json_set и путь, который молча ничего не находит

Свежий модуль стандартной сборки, которого нет в старых руководствах: ngx_http_json_module. Он достаёт значение из JSON прямо в конфиге - без njs и без похода в приложение.

/etc/nginx/nginx.confhttp
json_set $user_name $request_body user.name;
json_max_depth 8;

Путь пишется точками. И вот тут ловушка: похожие на JSON Pointer записи проверку проходят, а значения не дают. Один и тот же заголовок {"user":{"name":"бобр"},"items":["раз","два"]}, разные пути:

путь что вернулось
user.name бобр
user {"name":"бобр"} - весь вложенный объект
items ["раз","два"]
user/name пусто, nginx -t доволен
/user/name пусто, nginx -t доволен
items.0 пусто: элемент массива так не достать
глубже json_max_depth пусто

Битый JSON тоже даёт пустое значение и ни строки в логе. То есть все ошибки здесь выглядят одинаково - пустая переменная, - и различать их придётся прогоном, а не чтением конфига.

Вторая тонкость: $request_body заполняется, только когда тело реально прочитано. С return в том же location переменная пуста, с proxy_pass - работает:

/etc/nginx/conf.d/api.confhttp server location /orders
proxy_set_header X-User $user_name;
proxy_pass http://app:8000;

Другие способы дойти до приложения

Модуль Когда нужен
fastcgi_pass PHP через php-fpm - разобран в седьмом разделе
uwsgi_pass Python через uWSGI: uwsgi_pass unix:/run/app.sock; плюс include uwsgi_params;
scgi_pass тот же протокол, но проще; старые Python- и Perl-приложения
grpc_pass gRPC: grpc_pass grpc://app:9000; или grpcs://, обязательно поверх HTTP/2
memcached_pass отдать значение прямо из memcached, не будя приложение; ключ - в $memcached_key

grpc_pass стоит запомнить отдельно: gRPC внутри - это HTTP/2, поэтому обычный proxy_pass для него не годится, а на порту нужен http2 on.

Правка ответа на лету

sub_filter заменяет текст в теле - спасает при переезде домена, когда в вёрстке остались абсолютные ссылки, а править приложение нельзя:

/etc/nginx/conf.d/shop.local.confhttp server location /
sub_filter 'http://old.shop.local' 'https://shop.local';
sub_filter_once off;
sub_filter_types text/html text/css;

Плата - разбор тела каждого ответа, поэтому это временная мера, а не архитектура. Рядом: ssi собирает страницу из кусков прямо в nginx, addition приклеивает ответ подзапроса до или после основного без разбора тела, gunzip распаковывает ответ бэкенда для клиента, который сжатия не понимает.

Файлы, картинки и мелочи

  • image_filter - изменить размер, повернуть, обрезать картинку на лету; прожорлив по процессору, результат обязательно кешировать.
  • dav - загрузка и удаление файлами методами PUT, DELETE, MKCOL. Включать только с ограничением доступа: помни CVE-2026-27654 из двенадцатого раздела.
  • mp4 и flv - перемотка видео по времени без скачивания всего файла; slice режет большой файл на куски для кеша.
  • userid ставит клиенту cookie-идентификатор ($uid_got, $uid_set), charset дописывает и перекодирует кодировку, empty_gif отдаёт однопиксельный gif из памяти, random_index выдаёт случайный файл каталога.

Совсем другой мир: почта

Кроме http и stream есть третий корневой блок - mail: прокси для IMAP, POP3 и SMTP с терминацией TLS и внешней авторизацией.

/etc/nginx/nginx.conf
mail {
    server_name mail.shop.local;
    auth_http   http://app:8000/mail/auth;

    server {
        listen 993 ssl;
        protocol imap;
        proxy_pass_error_message on;
    }
}

nginx принимает соединение, спрашивает у твоего http-сервиса, куда направить пользователя, и соединяет его с нужным почтовым сервером. Задача узкая, но если она твоя - отдельный прокси заводить не нужно.

Что ломается без этого

Дважды написанная логика. Приложение, которое парсит JSON только затем, чтобы положить поле в заголовок, - это json_set. Скрипт, склеивающий страницу из двух кусков, - это ssi или addition. Сервис, распаковывающий ответ соседа, - это gunzip. Каждая такая замена стоит своего процесса, своего деплоя и своего дежурства.

Обратная ошибка тоже дорогая: sub_filter на всех ответах и image_filter без кеша выглядят как экономия, а стоят процессорного времени на каждом запросе. Оба модуля - временная мера, у которой должен быть срок.

Зачем это в работе

На разборе инцидента полезнее всего помнить не синтаксис, а список существующего. «Нам нужен сервис, который подменит домен в html» - это одна строка конфига и пятнадцать минут. «Нам нужно вытащить поле из тела запроса для маршрутизации» - json_set вместо njs, то есть без кода в рабочем процессе.

И обратная сторона: nginx -V стоит смотреть первым делом на чужом сервере. Половина «у нас это не работает» объясняется тем, что модуля там просто нет.

Теперь сам

В конфиг добавили строку image_filter resize 200 -;, nginx -t ругается unknown directive. Коллега советует пересобрать nginx из исходников. Что проверить до этого?

Ответ: сначала nginx -V - если модуль собран, дело не в нём. Дальше - дистрибутив: в пакетах nginx.org и в debian-образе image_filter лежит отдельным файлом /etc/nginx/modules/ngx_http_image_filter_module.so, и нужен только load_module .../ngx_http_image_filter_module.so; первой строкой nginx.conf плюс установка пакета nginx-module-image-filter. Пересборка из исходников нужна лишь там, где пакета нет вовсе, - например в alpine-образе, где этого модуля не собрано.

Главное

Стандартная сборка шире курса: uwsgi_pass, scgi_pass, grpc_pass и memcached_pass - другие протоколы до приложения; sub_filter, ssi, addition, gunzip - правка ответа; dav, mp4, slice, image_filter - файлы; json_set достаёт значение из JSON прямо в конфиге, но путь пишется точками, а похожие записи со слешами молча возвращают пустое. Есть третий корневой блок mail. Главное правило справочника: «стандартная сборка» у каждого своя - в официальном alpine-образе нет image_filter, xslt, degradation и perl, а в debian-образе они есть, но только через load_module. Смотри nginx -V раньше, чем пишешь директиву.

Комментарии

Пока нет комментариев. Будь первым!

Оставить комментарий

Комментарий появится после проверки. Email не публикуется. Войти, чтобы не вводить имя каждый раз.