# теория · шаг 1 из 3
Шесть решений над каждым запросом
Коротко
Это главный урок раздела: всё остальное в курсе - подробности к нему.
- На каждый запрос nginx принимает фиксированную цепочку из шести решений:
какой
server→ какойlocation→ не выйти ли сразу → откуда брать содержимое → чем обвесить ответ → что записать в лог. - Порядок НЕ зависит от того, как написан конфиг, и не меняется никогда.
- Поэтому любую поломку «отдаёт не то» разбирают, проходя список сверху вниз: не тот сайт - решение 1, не тот файл - 2 или 4, внезапный редирект - 3, пропали заголовки - 5.
- Каждый следующий раздел курса - подробный разбор одного из шести решений.
Если цепочка решений уже в голове - листай до «Теперь сам».
На каком шаге сломалось
Симптом с боевого сервера: на домене admin.shop.local вместо админки
открывается главная страница магазина. Конфиги обоих сайтов на месте, оба
nginx -t проходят.
Прежде чем читать дальше - на каком этапе обработки это могло произойти и сколько таких этапов вообще бывает?
Ответ на второй вопрос: шесть. Ответ на первый - на самом первом, и в конце урока станет понятно, почему остальные пять можно даже не проверять.
На что это похоже
Посылка в сортировочном центре проходит фиксированный набор станций, и порядок станций не зависит от того, что написано на коробке.
Сначала определяют город - по индексу, и только по нему. Потом внутри города определяют участок. Потом смотрят, не надо ли вернуть отправителю - если надо, дальше посылка не едет вообще. Потом решают, откуда её брать: она уже на складе или её надо получить у поставщика. Потом клеят наклейки. И в самом конце записывают в журнал, что и когда отправили.
Никакая надпись на коробке не заставит наклеить наклейку раньше, чем определён город. Ровно так же ни одна директива в конфиге не сработает раньше своего решения.
Механизм: шесть решений
Список короткий, и его стоит держать в голове целиком. Слева - вопрос, справа - то, из чего nginx берёт на него ответ.
Правило
Любую поломку «отдаёт не то» разбирай, проходя список сверху вниз, и
останавливайся на первом решении, которое дало не тот результат. Проверять
пятое, не проверив первое, - потерянное время: если запрос попал не в тот
server, всё остальное в конфиге отношения к делу не имеет.
Разбор: живой запрос по шагам
Клиент делает GET /api/cart с заголовком Host: shop.local, соединение
пришло на порт 80.
Решение 1 - кто отвечает. nginx смотрит на все server-блоки, которые
слушают 80-й порт, и ищет среди них тот, чей server_name совпадает с
shop.local. Не нашёл - берёт default_server, а если и его нет - первый блок
на этом порту. Приложение тут ни при чём: выбор идёт только по порту и
заголовку Host.
Решение 2 - какой location. Внутри выбранного блока сравниваются пути. У
/api/cart может быть несколько кандидатов: location /, location /api/ и
какая-нибудь регуляркаРазбирается в разделе 4, глава «Как выбирается location»: Пять форм записи location - шаблон вроде ~ \.php$,
под который подходит целое семейство адресов. Победит не первый и не самый очевидный, а тот, кого
выберут довольно неинтуитивные правила приоритета - им посвящён целый раздел.
Решение 3 - не закончить ли прямо здесь. Если в выбранном блоке есть
return 301 ..., дальше не происходит ничего: клиент получает редирект. Ни
файлов, ни бэкендов.
Решение 4 - откуда брать содержимое. Развилка на две ветки: либо путь
превращается в путь на диске (root, alias, try_files), либо запрос уходит
на бэкенд (proxy_pass). Одновременно и то и другое не бывает.
Решение 5 - чем обвесить ответ. Заголовки, сжатие, кеш-директивы.
Решение 6 - что записать в лог. Строка появляется ПОСЛЕ того, как ответ отправлен, - поэтому в ней уже известны и код ответаКод ответаПервая цифра говорит, что делать дальше: 2 - готово, 3 - иди по другому адресу, 4 - запрос выполнить нельзя, 5 - сломалось на сервере. Остальные две уточняют., и размер, и время.
Разбор: почему server_name не фильтрует
Наивное правило звучит так: «в блоке написано server_name shop.local, значит
на другие имена он не ответит». Вот конфиг, на котором это неверно.
server {
listen 80;
server_name shop.local;
root /var/www/shop;
}
Запрос с чужим именем:
curl -s -o /dev/null -w '%{http_code}\n' -H 'Host: evil.example' http://127.0.0.1/
200
Двести. Магазин ответил на имя, которого не знает.
Причина - в решении 1: nginx обязан выбрать какой-то блок из тех, что слушают
порт. Он ищет совпадение по имени, не находит, ищет default_server, не
находит и берёт первый блок на этом порту. Отказаться отвечать он не может:
на порту кто-то должен ответить.
Отсюда и объяснение симптома из начала урока. Если админка объявлена в файле,
который не попал в собранный конфиг (лежит в sites-available без ссылки,
назван .conf.bak), то запрос к admin.shop.local не находит своего блока и
достаётся магазину. Проверять при этом location, root и права на файлы -
бесполезно: сломалось на первом решении.
Правильный способ не отвечать на чужие имена - завести блок-заглушку, который станет умолчанием:
server {
listen 80 default_server;
server_name _;
return 444;
}
Код 444 - особый: nginx закрывает соединение, не отвечая вовсе. Подробности
про выбор блока и про default_server - в разделе про то, кто отвечает.
Что ломается без этого
«Открывается чужой сайт». Решение 1: имя не совпало, ответил блок по умолчанию или первый на порту.
«Отдаётся не тот файл» или «404 на существующий файл». Решение 2 или 4:
выбран другой location либо путь на диске собрался не так, как ожидалось.
«Внезапный редирект в цикл». Решение 3: сработал return или rewrite,
до содержимого дело не дошло.
«Пропал заголовок безопасности». Решение 5, и почти всегда это наследование
add_header - отдельная ловушка следующего раздела.
Зачем это в работе
Это единственная схема курса, которую стоит помнить наизусть. Она работает даже с чужим конфигом на пятьсот строк, потому что порядок решений не зависит от того, как конфиг написан, - а значит, разбор всегда начинается в одном и том же месте.
Практически это выглядит так: вместо чтения конфига сверху вниз задаёшь шесть вопросов по очереди и на первом же несовпадении получаешь ответ. Разница по времени - десятки минут на каждом инциденте.
Теперь сам
На сервере два сайта. Запрос к https://shop.local/static/app.css возвращает
301 на https://shop.local/. Файл на диске есть, права верные, location
/static/ в конфиге объявлен. На каком решении сломалось и что смотреть?
Ответ. На третьем. Права и наличие файла относятся к решению 4, но до него
дело не дошло: раз пришёл 301, сработал return или rewrite. Смотреть надо
две вещи: return на уровне самого server (он выполняется до выбора
location и бьёт всё) и rewrite внутри выбранного блока. Проверка - nginx
-T | grep -n "return\|rewrite" плюс rewrite_log on с уровнем notice в
error_log, который покажет, какая именно строка сработала. Смотреть права на
файл в этой ситуации бессмысленно: цепочка оборвалась раньше.
Главное
nginx обрабатывает запрос как фиксированную цепочку из шести решений: сервер → location → выход → источник содержимого → заголовки → лог. Порядок не зависит от того, как написан конфиг, поэтому по нему диагностируется любая поломка - сверху вниз, до первого решения, давшего не тот результат.
Комментарии
Пока нет комментариев. Будь первым!
Оставить комментарий