[Настройка Linux, Системное администрирование, Nginx, *nix] Nginx. Фазы обработки запроса. Практика
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Хабру катастрофически не хватает такого формата постов как "продолжение" или "дополнение". После написания статьи зачастую появляется материал, который хотелось бы добавить к сказанному, но update'ить статью, с её сроком жизни в 1-2 дня, бессмысленно, а писать в комментариях невозможно из-за объёма материала. В то же время этого материала может быть недостаточно для новой статьи, да и, в силу того, что он сильно перекликается с предыдущей статьёй, придется либо постоянно её цитировать, либо оставлять пробелы, подразумевая, что читатель понимает о чем идет речь.В итоге дополнительный материал, местами более важный чем сама статья, копится, пылится в заметках и пропадает с концами.Так бы случилось и с этой статьей, но недосказанность заставляет вернуться к теме, так как разбор вопроса "нужны ли теоретические знания порядка прохождения запроса на практике" может помочь избежать составления неработающих конфигов. Поэтому продолжим разговор.Для того чтобы понять как возникают подобные ошибки пройдёмся по хронологии создания конфига. Допустим, у нас был сайт с разделом, доступ в который осуществляется по платной подписке и, для особо жадных пользователей, мы отдаём 402-й HTTP код ответа. Тогда, в крайне упрощенном виде, начальная конфигурация имеет вид:
add_header "Content-Type" "text/html; charset=UTF-8" always;
log_format example_com '$request_uri\t$msec\t$status';
access_log /var/log/nginx/example_com.log example_com;
server {
listen *:80;
server_name .example.com;
location /pay {
return 402 'Pay: Money, money, money\n';
}
}
$ GET -S example.com/pay ; GET -S example.com/pay
GET http://example.com/pay
402 Payment Required
Pay: Money, money, money
GET http://example.com/pay
402 Payment Required
Pay: Money, money, money
$ tail -F /var/log/nginx/example_com.log
/pay 1626155551.311 402
/pay 1626155551.648 402
Эти пользователи-крохоборы оказались не только мелочными, но и мстительными и устроили DDoS-атаку в виде HTTP-флуда на данный раздел. Чтобы отсеять высокочастотные запросы администратор решает воспользоваться директивой limit_req и отсечь паразитные запросы частотностью свыше одного в секунду:
limit_req_zone $binary_remote_addr zone=limit402:20m rate=1r/s;
server {
listen *:80;
server_name .example.com;
location /pay {
limit_req zone=limit402 nodelay;
return 402 'Pay: Money, money, money\n';
}
}
Однако, ничего из ожидаемого не происходит:
$ GET -Sd example.com/pay ; GET -Sd example.com/pay
GET http://example.com/pay
402 Payment Required
GET http://example.com/pay
402 Payment Required
Как определены фазы в Nginx
typedef enum {
NGX_HTTP_POST_READ_PHASE = 0,
NGX_HTTP_SERVER_REWRITE_PHASE,
NGX_HTTP_FIND_CONFIG_PHASE,
NGX_HTTP_REWRITE_PHASE,
NGX_HTTP_POST_REWRITE_PHASE,
NGX_HTTP_PREACCESS_PHASE,
NGX_HTTP_ACCESS_PHASE,
NGX_HTTP_POST_ACCESS_PHASE,
NGX_HTTP_PRECONTENT_PHASE,
NGX_HTTP_CONTENT_PHASE,
NGX_HTTP_LOG_PHASE
} ngx_http_phases;
Модуль ngx_http_limit_req_module исполняет свои функции на этапе NGX_HTTP_PREACCESS_PHASE, в то время как ngx_http_rewrite_module работает в фазе NGX_HTTP_REWRITE_PHASE, как следствие, директива return завершает обработку запроса и ход до PREACCESS-фазы уже не доходит.Значит, для решения проблемы нам необходимо "поменять" фазы местами. Конечно, сделать мы этого не можем, но можем совершить перенаправление, частично повторив цикл прохождения фаз. Сделать это необходимо после этапа NGX_HTTP_PREACCESS_PHASE. Фаза NGX_HTTP_POST_ACCESS_PHASE является служебной, в фазах NGX_HTTP_ACCESS_PHASE и NGX_HTTP_LOG_PHASE нет возможности выполнить перенаправление, значит, остаются только NGX_HTTP_CONTENT_PHASE и NGX_HTTP_PRECONTENT_PHASE. В последней фазе нам вполне подходит модуль ngx_http_try_files_module и его директива try_files:
limit_req_zone $binary_remote_addr zone=limit402:20m rate=1r/s;
server {
listen *:80;
server_name .example.com;
location /pay {
limit_req zone=limit402 nodelay;
try_files $uri @fallback;
}
location @fallback {
return 402 'Fallback: Money, money, money\n';
}
}
И теперь всё работает именно в том порядке, который нам требовался:
$ GET -S example.com/pay ; GET -S example.com/pay
GET http://example.com/pay
402 Payment Required
Fallback: Money, money, money
GET http://example.com/pay
503 Service Temporarily Unavailable
<html>
<head><title>503 Service Temporarily Unavailable</title></head>
<body>
<center><h1>503 Service Temporarily Unavailable</h1></center>
<hr><center>nginx</center>
</body>
</html>
Вспоминая из манула, о том, что в следующем примере директива try_files
location / {
try_files $uri @fallback;
}
аналогична директивам
location / {
error_page 404 = @fallback;
log_not_found off;
}
можем привести наш конфиг к более "популярному" виду:
limit_req_zone $binary_remote_addr zone=limit402:20m rate=1r/s;
server {
listen *:80;
server_name .example.com;
location /pay {
limit_req zone=limit402 nodelay;
error_page 404 = @fallback;
log_not_found off;
}
location @fallback {
return 402 'Fallback: Money, money, money\n';
}
}
$ GET -Sd example.com/pay ; GET -Sd example.com/pay
GET http://example.com/pay
402 Payment Required
GET http://example.com/pay
503 Service Temporarily Unavailable
Всё также работает, как и требовалось, но, для острастки, убедимся в отладчике, что мы не ошиблись в наших размышлениях:debug
$ grep -E '(limit|HTTP|using|finalize|phase)' /var/log/nginx/error.log | grep -vF generic
2021/07/13 09:59:39 [debug] 38383#0: *15 http request line: "GET /pay HTTP/1.1"
2021/07/13 09:59:39 [debug] 38383#0: *15 rewrite phase: 1
2021/07/13 09:59:39 [debug] 38383#0: *15 using configuration "/pay"
2021/07/13 09:59:39 [debug] 38383#0: *15 rewrite phase: 3
2021/07/13 09:59:39 [debug] 38383#0: *15 post rewrite phase: 4
2021/07/13 09:59:39 [debug] 38383#0: *15 limit_req[0]: 0 0.000
2021/07/13 09:59:39 [debug] 38383#0: *15 access phase: 8
2021/07/13 09:59:39 [debug] 38383#0: *15 access phase: 9
2021/07/13 09:59:39 [debug] 38383#0: *15 access phase: 10
2021/07/13 09:59:39 [debug] 38383#0: *15 post access phase: 11
2021/07/13 09:59:39 [debug] 38383#0: *15 content phase: 14
2021/07/13 09:59:39 [debug] 38383#0: *15 content phase: 15
2021/07/13 09:59:39 [debug] 38383#0: *15 content phase: 16
2021/07/13 09:59:39 [debug] 38383#0: *15 content phase: 17
2021/07/13 09:59:39 [debug] 38383#0: *15 http finalize request: 404, "/pay?" a:1, c:1
2021/07/13 09:59:39 [debug] 38383#0: *15 using location: @fallback "/pay?"
2021/07/13 09:59:39 [debug] 38383#0: *15 rewrite phase: 3
2021/07/13 09:59:39 [debug] 38383#0: *15 HTTP/1.1 402 Payment Required
2021/07/13 09:59:39 [debug] 38383#0: *15 http write filter limit 0
2021/07/13 09:59:39 [debug] 38383#0: *15 http finalize request: 0, "/pay?" a:1, c:2
2021/07/13 09:59:39 [debug] 38383#0: *15 http finalize request: -4, "/pay?" a:1, c:1
2021/07/13 09:59:39 [debug] 38383#0: *16 http request line: "GET /pay HTTP/1.1"
2021/07/13 09:59:39 [debug] 38383#0: *16 rewrite phase: 1
2021/07/13 09:59:39 [debug] 38383#0: *16 using configuration "/pay"
2021/07/13 09:59:39 [debug] 38383#0: *16 rewrite phase: 3
2021/07/13 09:59:39 [debug] 38383#0: *16 post rewrite phase: 4
2021/07/13 09:59:39 [debug] 38383#0: *16 limit_req[0]: -3 0.650
2021/07/13 09:59:39 [error] 38383#0: *16 limiting requests, excess: 0.650 by zone "limit402", client: 12.34.56.78, server: example.com, request: "GET /pay HTTP/1.1", host: "example.com"
2021/07/13 09:59:39 [debug] 38383#0: *16 http finalize request: 503, "/pay?" a:1, c:1
2021/07/13 09:59:39 [debug] 38383#0: *16 HTTP/1.1 503 Service Temporarily Unavailable
2021/07/13 09:59:39 [debug] 38383#0: *16 http write filter limit 0
2021/07/13 09:59:39 [debug] 38383#0: *16 http finalize request: 0, "/pay?" a:1, c:1
Первый запрос с limit_req[0]: 0 0.000 был перенаправлен из локейшина /pay в @fallback, затем он совершил возврат в REWRITE-фазу и завершился с 402-м ответом. Второй, не уложившись в одну секунду (limit_req[0]: -3 0.650) закончился 503-м кодом без какого-либо перенаправления.На сим всё. До следующего продолжения.
===========
Источник:
habr.com
===========
Похожие новости:
- [Системное администрирование, DevOps, Облачные сервисы, Распределённые системы] DRS как средство оптимизации размещения виртуальных машин в облаке Mail.ru Cloud Solutions
- [Системное администрирование, Виртуализация, Хранение данных, Облачные сервисы] Вебинар «Выбираем облачные системы хранения для ваших сервисов: актуальные практики для любого проекта»
- [Open source, Системное программирование, *nix, Софт] Microsoft рассказала о собственном Linux-дистрибутиве CBL-Mariner
- [Информационная безопасность, Системное администрирование, Сетевые технологии] SoftEther VPN — быстрая настройка
- [Настройка Linux, *nix, Разработка на Raspberry Pi] Использование IceWM и Raspberry Pi в качестве основного PC: делюсь темой, конфигурацией и несколькими советами (перевод)
- [Информационная безопасность, Системное администрирование, IT-инфраструктура, Разработка под Windows, Софт] Проблема использования RunAs на серверах
- [JavaScript, Node.JS] Создаем свой сайт или блог на Ghost в образе Docker
- [Системное администрирование, *nix, Хранение данных] Траблшутинг DRBD9 в LINSTOR
- [Настройка Linux] Настройка ядра Linux для повышения производительности памяти
- [Настройка Linux] Архитектура контейнеров, часть 2. Пользовательское пространство
Теги для поиска: #_nastrojka_linux (Настройка Linux), #_sistemnoe_administrirovanie (Системное администрирование), #_nginx, #_*nix, #_nginx, #_nastrojka_linux (
Настройка Linux
), #_sistemnoe_administrirovanie (
Системное администрирование
), #_nginx, #_*nix
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 02:29
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Хабру катастрофически не хватает такого формата постов как "продолжение" или "дополнение". После написания статьи зачастую появляется материал, который хотелось бы добавить к сказанному, но update'ить статью, с её сроком жизни в 1-2 дня, бессмысленно, а писать в комментариях невозможно из-за объёма материала. В то же время этого материала может быть недостаточно для новой статьи, да и, в силу того, что он сильно перекликается с предыдущей статьёй, придется либо постоянно её цитировать, либо оставлять пробелы, подразумевая, что читатель понимает о чем идет речь.В итоге дополнительный материал, местами более важный чем сама статья, копится, пылится в заметках и пропадает с концами.Так бы случилось и с этой статьей, но недосказанность заставляет вернуться к теме, так как разбор вопроса "нужны ли теоретические знания порядка прохождения запроса на практике" может помочь избежать составления неработающих конфигов. Поэтому продолжим разговор.Для того чтобы понять как возникают подобные ошибки пройдёмся по хронологии создания конфига. Допустим, у нас был сайт с разделом, доступ в который осуществляется по платной подписке и, для особо жадных пользователей, мы отдаём 402-й HTTP код ответа. Тогда, в крайне упрощенном виде, начальная конфигурация имеет вид: add_header "Content-Type" "text/html; charset=UTF-8" always;
log_format example_com '$request_uri\t$msec\t$status'; access_log /var/log/nginx/example_com.log example_com; server { listen *:80; server_name .example.com; location /pay { return 402 'Pay: Money, money, money\n'; } } $ GET -S example.com/pay ; GET -S example.com/pay
GET http://example.com/pay 402 Payment Required Pay: Money, money, money GET http://example.com/pay 402 Payment Required Pay: Money, money, money $ tail -F /var/log/nginx/example_com.log
/pay 1626155551.311 402 /pay 1626155551.648 402 limit_req_zone $binary_remote_addr zone=limit402:20m rate=1r/s;
server { listen *:80; server_name .example.com; location /pay { limit_req zone=limit402 nodelay; return 402 'Pay: Money, money, money\n'; } } $ GET -Sd example.com/pay ; GET -Sd example.com/pay
GET http://example.com/pay 402 Payment Required GET http://example.com/pay 402 Payment Required typedef enum {
NGX_HTTP_POST_READ_PHASE = 0, NGX_HTTP_SERVER_REWRITE_PHASE, NGX_HTTP_FIND_CONFIG_PHASE, NGX_HTTP_REWRITE_PHASE, NGX_HTTP_POST_REWRITE_PHASE, NGX_HTTP_PREACCESS_PHASE, NGX_HTTP_ACCESS_PHASE, NGX_HTTP_POST_ACCESS_PHASE, NGX_HTTP_PRECONTENT_PHASE, NGX_HTTP_CONTENT_PHASE, NGX_HTTP_LOG_PHASE } ngx_http_phases; limit_req_zone $binary_remote_addr zone=limit402:20m rate=1r/s;
server { listen *:80; server_name .example.com; location /pay { limit_req zone=limit402 nodelay; try_files $uri @fallback; } location @fallback { return 402 'Fallback: Money, money, money\n'; } } $ GET -S example.com/pay ; GET -S example.com/pay
GET http://example.com/pay 402 Payment Required Fallback: Money, money, money GET http://example.com/pay 503 Service Temporarily Unavailable <html> <head><title>503 Service Temporarily Unavailable</title></head> <body> <center><h1>503 Service Temporarily Unavailable</h1></center> <hr><center>nginx</center> </body> </html> location / {
try_files $uri @fallback; } location / {
error_page 404 = @fallback; log_not_found off; } limit_req_zone $binary_remote_addr zone=limit402:20m rate=1r/s;
server { listen *:80; server_name .example.com; location /pay { limit_req zone=limit402 nodelay; error_page 404 = @fallback; log_not_found off; } location @fallback { return 402 'Fallback: Money, money, money\n'; } } $ GET -Sd example.com/pay ; GET -Sd example.com/pay
GET http://example.com/pay 402 Payment Required GET http://example.com/pay 503 Service Temporarily Unavailable $ grep -E '(limit|HTTP|using|finalize|phase)' /var/log/nginx/error.log | grep -vF generic
2021/07/13 09:59:39 [debug] 38383#0: *15 http request line: "GET /pay HTTP/1.1" 2021/07/13 09:59:39 [debug] 38383#0: *15 rewrite phase: 1 2021/07/13 09:59:39 [debug] 38383#0: *15 using configuration "/pay" 2021/07/13 09:59:39 [debug] 38383#0: *15 rewrite phase: 3 2021/07/13 09:59:39 [debug] 38383#0: *15 post rewrite phase: 4 2021/07/13 09:59:39 [debug] 38383#0: *15 limit_req[0]: 0 0.000 2021/07/13 09:59:39 [debug] 38383#0: *15 access phase: 8 2021/07/13 09:59:39 [debug] 38383#0: *15 access phase: 9 2021/07/13 09:59:39 [debug] 38383#0: *15 access phase: 10 2021/07/13 09:59:39 [debug] 38383#0: *15 post access phase: 11 2021/07/13 09:59:39 [debug] 38383#0: *15 content phase: 14 2021/07/13 09:59:39 [debug] 38383#0: *15 content phase: 15 2021/07/13 09:59:39 [debug] 38383#0: *15 content phase: 16 2021/07/13 09:59:39 [debug] 38383#0: *15 content phase: 17 2021/07/13 09:59:39 [debug] 38383#0: *15 http finalize request: 404, "/pay?" a:1, c:1 2021/07/13 09:59:39 [debug] 38383#0: *15 using location: @fallback "/pay?" 2021/07/13 09:59:39 [debug] 38383#0: *15 rewrite phase: 3 2021/07/13 09:59:39 [debug] 38383#0: *15 HTTP/1.1 402 Payment Required 2021/07/13 09:59:39 [debug] 38383#0: *15 http write filter limit 0 2021/07/13 09:59:39 [debug] 38383#0: *15 http finalize request: 0, "/pay?" a:1, c:2 2021/07/13 09:59:39 [debug] 38383#0: *15 http finalize request: -4, "/pay?" a:1, c:1 2021/07/13 09:59:39 [debug] 38383#0: *16 http request line: "GET /pay HTTP/1.1" 2021/07/13 09:59:39 [debug] 38383#0: *16 rewrite phase: 1 2021/07/13 09:59:39 [debug] 38383#0: *16 using configuration "/pay" 2021/07/13 09:59:39 [debug] 38383#0: *16 rewrite phase: 3 2021/07/13 09:59:39 [debug] 38383#0: *16 post rewrite phase: 4 2021/07/13 09:59:39 [debug] 38383#0: *16 limit_req[0]: -3 0.650 2021/07/13 09:59:39 [error] 38383#0: *16 limiting requests, excess: 0.650 by zone "limit402", client: 12.34.56.78, server: example.com, request: "GET /pay HTTP/1.1", host: "example.com" 2021/07/13 09:59:39 [debug] 38383#0: *16 http finalize request: 503, "/pay?" a:1, c:1 2021/07/13 09:59:39 [debug] 38383#0: *16 HTTP/1.1 503 Service Temporarily Unavailable 2021/07/13 09:59:39 [debug] 38383#0: *16 http write filter limit 0 2021/07/13 09:59:39 [debug] 38383#0: *16 http finalize request: 0, "/pay?" a:1, c:1 =========== Источник: habr.com =========== Похожие новости:
Настройка Linux ), #_sistemnoe_administrirovanie ( Системное администрирование ), #_nginx, #_*nix |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 02:29
Часовой пояс: UTC + 5