Top.Mail.Ru
OSEN-НИЙ SAAALEСкидка 50% на виртуальный хостинг и VDS
до 30.11.2025 Подробнее
Выберите продукт

Защита Nginx от всплесков трафика: limit_req, limit_conn, real_ip и практичные пресеты

Всплески трафика и агрессивные краулеры легко кладут бэкенд. Разбираем nginx rate limiting: limit_req, limit_conn, burst и real_ip — где и как настраивать, какие значения выбирать, как тестировать и не ломать прод. В конце — практичные пресеты.
Защита Nginx от всплесков трафика: limit_req, limit_conn, real_ip и практичные пресеты

Если у вас есть публичный веб‑сервис, вы рано или поздно столкнётесь со всплесками трафика: анонс в соцсетях, новостное упоминание, наплыв поисковых роботов, «жадные» парсеры или волна повторных запросов из‑за проблем на стороне клиента. В таких ситуациях Nginx — отличная первая линия защиты: он умеет сдерживать наплывы, справедливо распределять нагрузку и не давать бэкенду «задохнуться». В статье — как работают limit_req, limit_conn, burst, как корректно определить реальный IP через real_ip, и какие пресеты применить для статических сайтов, CMS и API.

Всплески vs DDoS: цель — сдержать, не навредив

Важно различать разовые всплески и спланированные атаки. Ограничители запросов — это про throttling и fair usage, а не про «магическую кнопку от всех бед». Они:

  • защищают бэкенд от временных перегрузок;
  • делают сервис предсказуемым под пиковыми нагрузками;
  • снижают эффект от грубых сканеров и «шумных» клиентов;
  • помогают в ddos mitigation как часть многоуровневой схемы.

Задача rate limiting — не «победить» атаку, а сохранить доступность и избежать каскадных отказов (очередей в БД, истощения пулов соединений, таймаутов).

Базовые инструменты Nginx: limit_req, limit_conn, burst

Как мыслить скоростями: ключи, зоны, алгоритм

limit_req ограничивает скорость запросов. Ключевые элементы:

  • Ключ — как идентифицируем клиента: чаще $binary_remote_addr (IP), но допустим токен/заголовок.
  • Зона — shared memory для счётчиков. Определяется в http через limit_req_zone.
  • Скоростьrate, например 10r/s.

Простейшая зона для ограничения по IP:

http {
    limit_req_zone $binary_remote_addr zone=perip:20m rate=10r/s;
    # ... остальная конфигурация
}

В локации включаем ограничение:

server {
    location / {
        limit_req zone=perip burst=20 nodelay;
    }
}

Алгоритм близок к «ведру с утечкой» (leaky bucket): запросы проходят с заданной средней скоростью, временные всплески сглаживаются очередью burst. Если очередь переполнена — вернётся ошибка (обычно 429).

Что такое burst и когда нужен nodelay

burst задаёт максимально допустимое накопление сверх лимита.

  • Без nodelay избыточные запросы ждут и «просачиваются» с допустимой скоростью.
  • С nodelay они проходят сразу, если есть кредит в очереди. Ниже задержка, выше риск микропиков нагрузки.

Типично: для API — небольшой burst с nodelay; для тяжёлых страниц — умеренный burst без nodelay, чтобы сгладить пики.

limit_conn: ограничение параллельных соединений

limit_conn ограничивает число одновременных соединений на ключ. Полезно при отдаче больших файлов, медиапотоков и WebSocket.

http {
    limit_conn_zone $binary_remote_addr zone=perip_conn:10m;
}

server {
    location /download/ {
        limit_conn perip_conn 2;
    }
}

С HTTP/2 помните: limit_conn считает соединения, а не потоки. Для контроля «запросов в единицу времени» подключайте limit_req.

Корректный клиентский IP: real_ip за балансировщиками и CDN

Если перед Nginx стоит внешний балансировщик/прокси/CDN, то $remote_addr будет адресом прокси. Лимитирование по IP сломается. Настройте доверенные источники и заголовки с реальным IP:

http {
    # Доверенные адреса прокси/балансировщиков (примерные подсети)
    set_real_ip_from 203.0.113.0/24;
    set_real_ip_from 198.51.100.0/24;

    # Заголовок, где прокси передаёт исходный IP
    real_ip_header X-Forwarded-For;

    # Разрешить рекурсивно извлекать первый «непрокси» IP
    real_ip_recursive on;
}

Доверяйте только тем подсетям, которые вы контролируете. Иначе клиент подменит заголовок и обойдёт лимиты. Если используете специфичный заголовок (например, от CDN), укажите его в real_ip_header.

Схема leaky bucket и burst в Nginx

Практичные пресеты для типовых сценариев

1) Статический сайт/лендинг с кэшируемыми ассетами

Цель — защитить корень сайта от всплесков, при этом ассеты (CSS/JS/шрифты/изображения) обычно дешёвые для Nginx и могут проходить чуть свободнее.

http {
    limit_req_zone $binary_remote_addr zone=perip:10m rate=10r/s;
    limit_conn_zone $binary_remote_addr zone=perip_conn:10m;
}

server {
    # Слегка строже к HTML/динамике
    location = / {
        limit_req zone=perip burst=20;
        limit_conn perip_conn 2;
    }

    # Остальные страницы
    location / {
        limit_req zone=perip burst=30;
        limit_conn perip_conn 4;
    }

    # Ассеты — «свободнее», чтобы не тормозить рендер
    location ~* \.(?:css|js|mjs|gif|jpe?g|png|webp|svg|ico|woff2?)$ {
        limit_req zone=perip burst=50 nodelay;
        limit_conn perip_conn 6;
        expires 7d;
        add_header Cache-Control "public";
    }
}

На простых сайтах на виртуальный хостинг такие лимиты особенно полезны: они сглаживают фронт пиков без задержек статики.

2) CMS (например, WordPress): отдельные лимиты для «горячих» эндпоинтов

Типичные узкие места — /wp-login.php и /xmlrpc.php, а также поисковые страницы. Для обычных посетителей оставим умеренные лимиты, для «горячих точек» — строгие.

http {
    limit_req_zone $binary_remote_addr zone=perip:20m rate=8r/s;     # База для IP
    limit_req_zone $binary_remote_addr zone=perip_strict:10m rate=1r/s; # Строгие точки
    limit_conn_zone $binary_remote_addr zone=perip_conn:10m;
}

server {
    # Базовый лимит для сайта
    location / {
        limit_req zone=perip burst=20;
        limit_conn perip_conn 4;
    }

    # Жёстко ограничить попытки логина
    location = /wp-login.php {
        limit_req zone=perip_strict burst=5 nodelay;
        limit_conn perip_conn 1;
        try_files $uri @php;
    }

    # XML-RPC — ещё строже или вовсе отключить, если не нужен
    location = /xmlrpc.php {
        limit_req zone=perip_strict burst=2;
        limit_conn perip_conn 1;
        try_files $uri @php;
    }

    # Админка и AJAX — умеренно
    location ~* ^/wp-admin/|^/wp-admin/admin-ajax\.php$ {
        limit_req zone=perip burst=10;
        limit_conn perip_conn 2;
        try_files $uri @php;
    }

    location @php {
        # Здесь прокси на PHP-FPM/апстрим
        proxy_pass http://php;
    }
}

Для безопасных правок конфигурации и обновлений WordPress пригодится стейджинг: смотрите разбор в статье wordpress-vds-staging-dns.

3) API/SPA: лимит по токену или заголовку, а не только по IP

Для API полезно ограничивать не IP, а «клиентскую сущность»: ключ, токен, ID устройства. Если ключа нет — отступайте к IP.

http {
    # Если есть ключ — используем его, иначе IP
    map $http_x_api_key $limit_key {
        ""      $binary_remote_addr;
        default  $http_x_api_key;
    }

    limit_req_zone $limit_key zone=perkey:50m rate=10r/s; # 50M ≈ >800k ключей
    limit_conn_zone $limit_key zone=perkey_conn:10m;
}

server {
    location /api/ {
        # Стандартный профиль: 10r/s, допуск 20 запросов сверху без задержек
        limit_req zone=perkey burst=20 nodelay;
        limit_conn perkey_conn 2;

        # Проброс к апстриму
        proxy_pass http://api_backend;
        proxy_set_header X-Request-ID $request_id;
    }

    # Более строгий профиль для чувствительных маршрутов
    location ~ ^/api/(auth|billing|orders) {
        limit_req zone=perkey burst=5;     # без nodelay — сгладить всплески
        limit_conn perkey_conn 1;
        proxy_pass http://api_backend;
    }
}

4) Раздача файлов и медиа: приоритизируем справедливость

Крупные загрузки, особенно с возобновлением, легко забивают полосу. Здесь уместен жёсткий контроль limit_conn по IP и умеренный limit_req на запросы.

http {
    limit_req_zone $binary_remote_addr zone=perip:10m rate=5r/s;
    limit_conn_zone $binary_remote_addr zone=perip_conn:10m;
}

server {
    location /media/ {
        limit_conn perip_conn 2;  # не даём открывать десятки потоков
        limit_req zone=perip burst=10;
        # Дополнительно можно регулировать скорость
        # limit_rate_after 1m;
        # limit_rate 512k;
    }
}

Коды ответов, заголовки и UX при ограничении

По умолчанию limit_req возвращает 503. На практике для rate limiting удобнее 429 (Too Many Requests) и заголовок Retry-After, чтобы клиент мог корректно ретраить.

http {
    # ... зоны ...
}

server {
    # Глобально поменяем статус
    limit_req_status 429;
    limit_conn_status 429;

    error_page 429 = @too_many;

    location @too_many {
        add_header Retry-After 60 always;
        add_header Content-Type text/plain;
        return 429 "Too Many Requests\n";
    }
}

Логи и целевая диагностика

Отделяйте логи ограниченных запросов от общей ленты — так проще калибровать значения без шумов.

http {
    map $status $log_limited {
        429  1;
        default 0;
    }

    log_format limited '$remote_addr - $remote_user [$time_local] '
                       '"$request" $status $body_bytes_sent '
                       '"$http_referer" "$http_user_agent"';
}

server {
    access_log /var/log/nginx/access.log;
    access_log /var/log/nginx/limited.log limited if=$log_limited;
}

Дополнительно помечайте ограниченные ответы заголовками, помня про кэш: используйте модификатор always.

Пример логов Nginx с 429 и Retry-After

Тестирование: как убедиться, что не сломали прод

Проверяйте конфиг перед перезагрузкой и используйте reload, а не restart:

nginx -t && sudo systemctl reload nginx

Смоделировать всплеск можно простыми инструментами. Пример с ab для страницы:

ab -n 200 -c 50 https://example.org/

И для API с авторизационным заголовком:

ab -n 300 -c 30 -H "X-API-Key: demo-123" https://example.org/api/ping

Запускайте проверки в тестовом окружении или в непиковое время. Смотрите долю 429, задержки и загрузку апстримов.

Производительность и размер зон

Зоны limit_req_zone и limit_conn_zone живут в общей памяти. Оценка: на 1 МБ хранится до ~16 тыс. записей (зависит от ключа и версии). На сайт со 100–200 тыс. уникальных IP/час закладывайте 10–20 МБ на зону.

  • HTTP/2: много параллельных запросов в одном соединении. Используйте limit_req, а limit_conn держите умеренным.
  • Keepalive: слишком агрессивный limit_conn ухудшает эффективность keepalive.
  • Вверх по стеку: не забывайте про worker_processes auto; и достаточные worker_connections.

Белые списки и служебные пути

Мониторинги, бэкенд‑обработчики, внутренние сети — желательно не ограничивать. Проще завести флажок и отключать лимиты условно.

http {
    geo $whitelist {
        default      0;
        10.0.0.0/8   1;
        192.168.0.0/16 1;
    }
}

server {
    location /healthz {
        if ($whitelist) { set $limit_bypass 1; }
        # Отдельный server без лимитов надёжнее
        return 200 'OK';
    }

    location / {
        if ($whitelist) { set $limit_bypass 1; }
        limit_req zone=perip burst=20;
        limit_conn perip_conn 4;
    }
}

Частые ошибки

  • Нет real_ip: все клиенты сливаются в IP балансировщика — лимиты не работают.
  • Слишком жёсткие значения: отрезаете легитимный трафик. Начинайте мягко, затем ужесточайте.
  • Одинаковый профиль для всего: выделяйте «горячие» пути в отдельные зоны.
  • Игнорирование burst: без очереди короткий пик превращается в ошибки.
  • Неучёт HTTP/2: один коннект — много потоков. Нужен limit_req, а не только limit_conn.
  • Одинаково душите ассеты и динамику: ухудшает UX и рендер.
  • Лимитируете служебные пути: /health, /metrics, вебхуки — держите в белом списке или на отдельном хосте.

Чек‑лист внедрения за 15 минут

  1. Включите корректный real_ip и доверяйте только своим прокси/балансировщикам.
  2. Создайте базовые зоны: limit_req_zone и limit_conn_zone по IP/ключу.
  3. Примените умеренный профиль к общим локациям и строгий — к «горячим» эндпоинтам.
  4. Настройте коды 429 и Retry-After, заведите отдельный лог ограничений.
  5. Проведите нагрузочный тест, проверьте долю 429 и латентность.
  6. Вынесите пресеты в include‑файл, чтобы быстро подкручивать значения.

Когда стоит пойти дальше

Если всплески регулярные или есть признаки распределённой атаки, комбинируйте лимитирование с кэшем на периметре, фильтрацией по сигнатурам/поведению и масштабированием. Для проектов с высокой интенсивностью трафика переход на VDS даёт изолированные ресурсы и предсказуемую сетевую производительность.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Чтобы выбрать удобную панель для администрирования, пригодится сравнительный обзор: vds-panels-2025-comparison.

Итог: limit_req, limit_conn, burst и корректный real_ip превращают хаотичный трафик в контролируемый. Начните с простых пресетов, включите логи — и доведите баланс между стабильностью и UX.

Поделиться статьей

Вам будет интересно

rsync для деплоев и бэкапов: быстрые ключи, инкрементальность и контроль прав OpenAI Статья написана AI Fastfox

rsync для деплоев и бэкапов: быстрые ключи, инкрементальность и контроль прав

rsync остаётся базовым инструментом для деплоя и резервного копирования. В статье — проверенные пресеты, инкрементальные бэкапы че ...
php-fpm status и ping: включаем, мониторим и ищем узкие места OpenAI Статья написана AI Fastfox

php-fpm status и ping: включаем, мониторим и ищем узкие места

Разделы status и ping в php-fpm — быстрый способ понять здоровье пула и найти узкие места под нагрузкой. Покажу, как включить и за ...
UFW на практике: быстрые правила для веб‑сервера, SSH и rate‑limit OpenAI Статья написана AI Fastfox

UFW на практике: быстрые правила для веб‑сервера, SSH и rate‑limit

UFW позволяет быстро закрыть лишние порты, оставить доступ к SSH и сайту и включить защиту от перебора. В статье — безопасный запу ...