Back to blog

Тюним Nginx

6/12/2025
nsvk13

Рекомендация: прежде чем заниматься тюнингом Nginx, пожалуйста, сделайте бекап конфигурации, вы делаете всё на свой страх и риск.

Рассмотрим ситуацию

Школьники дудосеры устроили нагрузочное тестирование и натравили на твой сервак какой-нибудь "jopasiski-3000", и бьют нам каналы syn-flood'ом, нам придётся отбивать эту херню.

Есть 3 варианта как поступить здесь:

  • Подключить DDosGuard
  • Использовать Cloudflare

Первый вариант нам может не подойти из-за отсутствия бюджета на данную защиту, остаётся Cloudflare и... Тюнинг Nginx!

(Об Cloudflare как-нибудь потом.)

Ну так чё делать то?

Блядь ёпта, nginx затюнить и отбить всю эту хуйню-муйню. Понятное дело оно особо при дидосах не спасет, но со сканерами и "jopasiski-3000" сможет справится.

В nginx есть параметр limit_req_zone, который ограничивает количество одновременныхх запросов с одного айпишника.

Пиздуем тюнить Nginx

Создаём файл по пути: /etc/nginx/conf.d/assholes.conf

geo $limited {
    default 1;
    192.168.1.1 0; # Этот IP не лимитируется
    10.0.0.0/24 0; # 10.0.0.0/24 тоже без ограничений
}

map $limited $limit {
    1 $binary_remote_addr;
    0 "";
}

limit_req_zone $limit zone=nsvk13:20m rate=200r/s;

limit_req_zone — ключ для отслеживания запросов.

$binary_remote_addr — системная переменная nginx, внутри хранит ip-адрес клиента.

zone=nsvk13:20m — произвольное имя зоны, 20m это объём памяти в мегабайтах для хранения данных. В этой зоне хранятся данные о количество запросов от каждого уникального клиента.

rate=200r/s — ограничение равное 200 запросов в секунды с одного ip-клиента.

Для рейта есть такая табличка

Сценарий                    rate      burst
-------------------------------------------
API с высокой нагрузкой     100r/s    200
Средний веб-сайт            50r/s     100
Анти-DDoS защита            10r/s     20
CDN или кеширующий прокси   500r/s    1000

Тестируем так:

ab -n 1000 -c 50 http://nsvk13.dev/
wrk -t4 -c100 -d10s http://nsvk13.dev/

И смотрим нет ли ошибок 503 Слишком дохуя запросов и корректно ли отрабатывает лимит.

А как рассчитать эту 20m памяти?..

Максимальное количество клиентов = размер зоны в байтах / размерзаписиклиента

Ладно сложно, на простом:

Пример расчёта для 20m (20 мегабайт = 20 х 1024 = 1024 = 20 971 520 байт):
20 971 529 / 128 = 163 840

То есть, зона 20m может хранить лимиты примерно для 163 тысяч уникальных клиентов одновременно.

А откуда взялось 128?

Как я написал выше, nginx хранит каждого уникального клиента (ключ $binary_remote_addr или другое значение), в зоне, используя примерно 128 байт на запись.

Есть такая табличка:

< 20 000 =  4m
~80 000  =  10m
~160 000 = 20m
500 000+ = 64m

Ещё можно настроить burst для резких пиков, burst позволяет превышать rate, прежде чем включиться жёсткий лимит.

Например

limit_req zone=nsvk13 burst=400 nodelay;

Клиенту разрешается до 400 мгновенных запросов, а затем он падает в ограничение 200r/s.

nodelay означает, что первые 400 запросов проходят сразу, а потом начинается строгий лимит.

Теперь по мапингам и гео хуйне

В первом блоке про гео

  1. Все юзеры получат $limited = 1 (по умолчанию).
  2. Те, кто с 192.168.1.1 или из .10.0.0.0/24, получат $limited = 0 и не будут ограничены.

Во втором блоке про мапинг

  1. Если $limited = 1, то $limit = $binary_remote_addr (IP-адрес клиента).
  2. Если $limited = 0, то $limit = "", и клиент не попадает в limit_req_zone.

Короче делаем что-то вроде белого списка и кто в него не входит — идёт нахуй! Надеюсь понятно объяснил.

Теперь чтобы вся эта поебота заработала, нужно прописать в нужный локейшен:

location / {
    limit_req zone=nsvk13 burst=10 nodelay;
    try_files $uri $uri/ index.php?$args;
}

Чтобы отдавтаь нужный стату при достижении лимита, делаем:

location / {
    limit_req_status: 429;
    limit_req zone=nsvk13 burst=10 nodealy;
    try_files $uri $uri/ /index.php?$args;
}

Возвращаем 429 слишком дохуя запросов, вместо станадртного 502.

Бездумно это настраивать не советую, могут пострадать обычные пользователи, а вот если вдумчиво сделать — спасёшь свою боевую кобылу от школоло-хакеров.