Зачем нужен Nginx, если приложение само умеет принимать запросы
Логичный вопрос: приложение умеет слушать порт и отвечать на HTTP-запросы само. Зачем перед ним ставят ещё одну программу? Разберём, что она берёт на себя и почему именно в ней вы будете искать следы половины инцидентов.
Что произойдёт, если убрать
Проще начать с обратного. Пусть приложение принимает запросы напрямую.
Первая же проблема — сертификат. Шифрование придётся настраивать внутри приложения, и в каждом следующем сервисе заново. Сертификаты истекают, их нужно обновлять, и теперь это забота десяти разных команд вместо одной.
Вторая — масштабирование. Пока экземпляр приложения один, всё работает. Как только нужно два, возникает вопрос, кто и по какому принципу распределяет запросы между ними.
Третья — статика. Картинки, стили и скрипты будет отдавать само приложение, тратя на это ресурсы, которые предназначались для бизнес-логики.
Четвёртая — все остальные запросы приходят прямо в приложение: и поисковые роботы, и сканеры уязвимостей, и любители подобрать пароль перебором. Фильтровать их тоже придётся коду.
Nginx — это программа, которую ставят перед приложением, чтобы снять с него все четыре задачи разом. Работает она как обратный прокси: принимает запрос от пользователя, передаёт внутрь, забирает ответ, возвращает обратно. Снаружи видно только её.
Что он делает
Терминирует шифрование. Соединение по HTTPS устанавливается с nginx, а дальше внутри сети запрос идёт по обычному HTTP. Сертификат лежит в одном месте, приложения о нём ничего не знают.
Балансирует нагрузку. Запросы распределяются между несколькими экземплярами приложения. Если один перестал отвечать, nginx перестаёт слать на него трафик — пользователь при этом ничего не заметит.
Отдаёт статику. Файлы, которые не меняются, уходят пользователю напрямую с диска, минуя приложение.
Кэширует. Ответы, одинаковые для всех, сохраняются и отдаются из памяти без обращения к приложению.
Ограничивает и фильтрует. Здесь настраиваются лимиты на частоту запросов с одного адреса, белые и чёрные списки, ограничение размера загружаемого файла, блокировка по географии.
Маршрутизирует. По адресу запроса решает, в какой именно сервис его направить: запросы на /api/ — в одно приложение, всё остальное — в другое.
Главное для поддержки: access-лог
Поскольку nginx встречает запрос первым, именно здесь пишется самая полная картина внешнего трафика — access-лог. Это основной источник ответа на вопрос «что вообще происходило».
В стандартной строке лога есть адрес клиента, время с точностью до секунды, метод и путь запроса, код ответа, размер ответа, реферер и User-Agent. Почти всегда в формат добавляют ещё время обработки запроса — и это самое ценное поле, потому что по нему видно не только что сломалось, но и что начало тормозить.
Что с этим делать при разборе заявки:
- найти конкретный запрос пользователя по времени и пути и увидеть, какой код он получил на самом деле — нередко это расходится с тем, что описал пользователь;
- посчитать, сколько таких ошибок было за период, и понять, единичный это случай или массовый;
- посмотреть распределение времени обработки и найти момент, когда оно начало расти;
- определить, дошёл ли запрос до приложения вообще: если в access-логе он есть, а в логах приложения его нет, ответ сформировал сам nginx.
Последний пункт стоит запомнить отдельно — он экономит часы. Разбирая ошибку, всегда полезно сначала понять, кто ответил: приложение или то, что стоит перед ним.
Ошибки, которые отдаёт сам nginx
Несколько кодов почти всегда означают, что проблема не в коде приложения:
502 Bad Gateway — nginx не смог получить ответ от приложения. Приложение не запущено, упало, слушает не тот порт или перезапускается прямо сейчас.
504 Gateway Timeout — приложение ответило, но слишком долго, и nginx не стал ждать. Обычно это тяжёлый запрос в базу, зависшая интеграция или таймаут, выставленный меньше реального времени обработки. Разница с 502 принципиальна: там связи не было вовсе, здесь связь была, но ответ не успел.
413 Request Entity Too Large — пользователь пытается загрузить файл крупнее разрешённого лимита. Классическая заявка «не загружается скан договора» решается одной строкой в конфигурации, а не доработкой приложения.
403 Forbidden от nginx — сработало ограничение по адресу, список доступа или права на файл. Отличить от 403 приложения легко: у nginx это простая HTML-страница, у приложения обычно JSON.
499 — нестандартный код, который nginx записывает, когда клиент закрыл соединение, не дождавшись ответа. В логах выглядит тревожно, но означает лишь, что пользователю надоело ждать и он обновил страницу. Массовые 499 — косвенный признак того, что сервис тормозит.
Практический вывод
Схема «пользователь → nginx → приложение» кажется очевидной, пока не начинаешь разбирать инцидент. Тогда выясняется, что каждый переход в этой цепочке — отдельная точка отказа, и первый вопрос при разборе всегда один: докуда запрос дошёл.
Ответ на него почти всегда лежит в access-логе, и поэтому доступ к нему стоит попросить раньше, чем он понадобится.
