Акция Панель управления ispmanager для VDS — первый месяц бесплатно
до 31.07.2026 Подробнее
Выберите продукт

Nginx 429 Too Many Requests: limit_req и limit_conn — настройка, realip и отладка

Код 429 в Nginx чаще всего связан с limit_req или limit_conn, но нередко возникает «ложно» за reverse proxy из‑за неправильного определения IP клиента. Разберём rate limiting, burst/nodelay, realip и быстрые приёмы отладки по логам.
Nginx 429 Too Many Requests: limit_req и limit_conn — настройка, realip и отладка

Почему Nginx отдаёт 429 Too Many Requests

Код 429 Too Many Requests в Nginx в большинстве случаев означает, что сработал один из встроенных лимитов: limit_req (частота запросов) или limit_conn (число одновременных соединений). Реже 429 возвращает само приложение (например, API реализует собственный rate limiting).

Чтобы быстро привести ситуацию в порядок, держите в голове два вопроса: что именно ограничиваем (запросы или соединения) и по какому ключу считаем (реальный клиентский IP или адрес прокси/балансировщика).

limit_req vs limit_conn: что именно вы ограничиваете

limit_req: ограничение запросов (r/s)

limit_req ограничивает среднюю скорость запросов на ключ (обычно IP). При превышении часть запросов может быть поставлена в очередь (если задан burst) либо сразу получит 429.

Важно: это не «жёсткий метроном». Механика похожа на leaky bucket: Nginx сглаживает рывки до среднего значения, и поведение сильно зависит от burst и nodelay.

limit_conn: ограничение одновременных соединений

limit_conn ограничивает именно параллельные соединения, а не запросы. С keep-alive соединения могут долго висеть без активности, а при HTTP/2 один TCP-коннект несёт много запросов. Поэтому limit_conn — хорошая страховка, но не замена limit_req для защиты API.

Схема работы limit_req: rate, burst-очередь и момент появления 429

Базовая настройка limit_req: зона, ключ, лимит

Любой rate limiting в Nginx начинается с зоны shared memory в контексте http. В зоне Nginx хранит счётчики по ключам. Если зона не объявлена, ограничивать нечем.

http {
    # Ключ — бинарный IP клиента (экономит память зоны)
    limit_req_zone $binary_remote_addr zone=perip_req:10m rate=5r/s;

    server {
        listen 80;
        server_name example.com;

        location /api/ {
            limit_req zone=perip_req;
            proxy_pass http://backend;
        }
    }
}
  • $binary_remote_addr — компактный ключ для IPv4/IPv6, обычно лучший выбор по памяти.
  • zone=perip_req:10m — имя и размер зоны. Размер подбирают по числу активных уникальных ключей.
  • rate=5r/s — средняя скорость на ключ: 5 запросов в секунду.

burst и nodelay: как очередь превращается в 429

Неожиданные 429 чаще всего появляются из-за неверных ожиданий от burst и nodelay: админ думает, что «разрешил всплески», а на деле либо создаёт очередь с задержками, либо начинает отстреливать запросы при пике.

burst: сколько «лишних» запросов можно пережить

burst разрешает кратковременный всплеск сверх rate. Лишние запросы будут поставлены в очередь и «выпущены» с ограниченной скоростью. Если очередь переполнится, Nginx вернёт 429.

location /api/ {
    limit_req zone=perip_req burst=20;
    proxy_pass http://backend;
}

Смысл: при лимите 5 r/s клиент сможет кратко «протолкнуть» пачку запросов, но получит задержку (они растянутся во времени). Для браузеров и фронтенд-сценариев это часто приемлемо.

nodelay: пропускать burst сразу (и быстрее получить 429)

С nodelay Nginx не будет искусственно задерживать запросы из burst-очереди: он пропустит их сразу до лимита burst, а всё, что выше, — мгновенно отрежет 429. Это часто лучше для API: «быстрый отказ» проще обработать ретраями, чем непредсказуемая задержка.

location /api/ {
    limit_req zone=perip_req burst=20 nodelay;
    proxy_pass http://backend;
}

Практический ориентир: для страниц и UI-ручек чаще подходит burst без nodelay; для API и интеграций — burst с nodelay, чтобы не копить латентность.

Если вам нужно быстро поднять Nginx с понятными лимитами и логированием на выделенной машине, удобнее делать это на VDS: проще управлять сетевыми слоями (прокси, балансировщики), realip и наблюдаемостью.

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

limit_conn на практике: как не «задушить» keep-alive и HTTP/2

limit_conn тоже требует зоны (в http) и применения (в server или location). Он полезен, когда нужно ограничить число параллельных соединений от одного ключа и защититься от клиентов, которые держат слишком много коннектов.

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

    server {
        listen 80;

        # Ограничить соединения на весь виртуальный хост
        limit_conn perip_conn 20;

        location / {
            proxy_pass http://backend;
        }
    }
}
  • Слишком низкий лимит при долгих keep-alive соединениях даст «мигание» и жалобы пользователей.
  • Для HTTP/2 один клиент может держать 1–2 TCP-соединения и всё равно делать много параллельных запросов: здесь чаще спасает limit_req.
  • Ключ должен соответствовать реальному клиенту. Если вы за прокси, сначала настройте realip, иначе все пользователи окажутся «одним клиентом».

Самая частая причина ложных 429: неправильный IP клиента за reverse proxy

Если Nginx стоит за балансировщиком, CDN или любым reverse proxy, то $remote_addr может быть адресом прокси, а не пользователя. В таком случае все реальные клиенты «сливаются» в один ключ, и лимиты срабатывают мгновенно: вы наблюдаете лавину 429 без реальной атаки.

Решение — настроить realip так, чтобы Nginx доверял только своим прокси и извлекал адрес клиента из заголовка (обычно X-Forwarded-For или профильного заголовка вашей инфраструктуры).

Правильный подход: доверяем только своим прокси (set_real_ip_from)

Нельзя принимать X-Forwarded-For от всех: клиент может подставить любой заголовок и обойти лимиты, подложив «чистый» IP. Поэтому обязательно задавайте доверенные адреса/подсети через set_real_ip_from.

http {
    # Доверяем только вашим прокси/балансировщикам/подсетям
    set_real_ip_from 192.0.2.10;
    set_real_ip_from 198.51.100.0/24;

    real_ip_header X-Forwarded-For;
    real_ip_recursive on;

    limit_req_zone $binary_remote_addr zone=perip_req:10m rate=5r/s;

    server {
        listen 80;

        location /api/ {
            limit_req zone=perip_req burst=20 nodelay;
            proxy_pass http://backend;
        }
    }
}
  • real_ip_header — из какого заголовка брать IP.
  • real_ip_recursive on — проходить по цепочке прокси в X-Forwarded-For и выбрать «первый недоверенный» адрес как клиентский.
  • set_real_ip_from — список доверенных источников. Это критично и для безопасности, и для корректного rate limiting.

Как проверить, что realip работает

Самая практичная проверка — временно расширить формат access log и вывести $remote_addr, $realip_remote_addr и $http_x_forwarded_for. Так вы увидите, кто сейчас считается «клиентом» для лимитов.

http {
    log_format rl_dbg '$remote_addr real=$realip_remote_addr xff="$http_x_forwarded_for" '
                      '"$request" $status rt=$request_time urt=$upstream_response_time';

    access_log /var/log/nginx/access_rl_dbg.log rl_dbg;
}

Если в $remote_addr всё ещё адрес балансировщика, значит set_real_ip_from задан неверно (не та подсеть/адрес) или есть ещё один слой прокси, который не учтён.

Отладка 429: как понять, какой лимит сработал

Когда жалуются на 429, администратору полезно быстро ответить на три вопроса: это лимиты Nginx или ответ приложения, какой ключ используется и как выглядит нагрузка (всплеск, бот, ретраи, медленный апстрим).

1) error_log: сообщения limit_req/limit_conn

Nginx обычно пишет в error log события срабатывания лимитов (в зависимости от уровня). Для точечной диагностики удобно временно включить отдельный error log на уровне notice для нужного server.

server {
    error_log /var/log/nginx/error_rate_limit.log notice;

    location /api/ {
        limit_req zone=perip_req burst=20 nodelay;
        proxy_pass http://backend;
    }
}
sudo tail -n 200 /var/log/nginx/error_rate_limit.log

2) access_log: срез по 429 и топ источников

Соберите топ по 429: какие IP/ключи и какие URI чаще всего упираются в ограничения.

sudo awk '$9==429 {print $1, $7}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head

Если вы за прокси и забыли realip, в первой колонке будет один и тот же адрес (балансировщик) — это почти гарантированный признак «ложных 429».

3) Отличаем 429 от Nginx и 429 от приложения

Если 429 возвращает Nginx из-за limit_req, запрос может вообще не уйти в upstream. В логах это обычно видно по пустым/нулевым upstream-полям (если вы их логируете) и по записям о limiting в error log.

Если 429 отдаёт приложение, Nginx проксирует ответ, и вы увидите нормальные upstream-тайминги. В спорных случаях полезно завести отдельный формат логов под API и логировать, например, $upstream_status и $upstream_response_time.

Пример отладочного access log с remote_addr, realip_remote_addr и X-Forwarded-For

Паттерны настройки: что ограничивать и по какому ключу

Ограничение «по IP на весь сайт» — самый простой старт, но не всегда лучший. Часто эффективнее ограничивать «смысловые» участки: API, тяжёлые эндпойнты, некешируемые методы. Про кеширование и диапазонные запросы, которые могут раздувать нагрузку, полезно почитать отдельно: Range-запросы и кеш в Nginx/Apache.

Лимит только для API и отдельно для тяжёлых ручек

Частый рабочий вариант: «лёгкие» API-эндпойнты получают более высокий лимит, «тяжёлые» (импорт, отчёты, генерация) — более низкий и с небольшим burst.

http {
    limit_req_zone $binary_remote_addr zone=api_light:10m rate=10r/s;
    limit_req_zone $binary_remote_addr zone=api_heavy:10m rate=2r/s;

    server {
        location /api/ {
            limit_req zone=api_light burst=30;
            proxy_pass http://backend;
        }

        location /api/import/ {
            limit_req zone=api_heavy burst=5 nodelay;
            proxy_pass http://backend;
        }
    }
}

Не используйте $http_x_forwarded_for как ключ напрямую

Использовать $http_x_forwarded_for напрямую почти всегда ошибка: заголовок может быть подделан, содержит список IP, бывает в разных форматах. Правильная схема: настроить realip и использовать $binary_remote_addr (после realip это будет «реальный» адрес клиента).

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

Виртуальный хостинг FastFox
Виртуальный хостинг для сайтов
Универсальное решение для создания и размещения сайтов любой сложности в Интернете от 95₽ / мес

Лимит по токену/ключу API: осторожно с логами

Для публичного API иногда логичнее считать не IP, а токен (например, из заголовка Authorization). Важно не утекать секретами в логи: если вы используете токен как ключ, заранее продумайте обезличивание (например, внутренний идентификатор ключа или хеш, который не позволяет восстановить секрет).

Если лимиты настроены, но 429 всё равно много

Проверьте ретраи клиентов и таймауты

Типовой сценарий: backend иногда отвечает медленно, клиент/прокси включает агрессивные ретраи, и вы получаете самоподдерживающийся «шторм» запросов, который ловит limit_req. В логах это выглядит как много одинаковых запросов подряд от одного ключа.

Согласуйте rate limiting с кешированием

Если часть запросов кешируется на уровне Nginx, имеет смысл делать более строгие лимиты для некешируемых эндпойнтов и более мягкие для кешируемых. Если кеш фактически не работает, лимиты будут срабатывать чаще, чем вы ожидали, потому что каждый запрос долетает до backend.

Оцените размер зон

Если уникальных ключей много (мобильные сети, корпоративный NAT, большой трафик), зоны должны быть достаточно крупными. Слишком маленькая shared memory зона может приводить к нестабильному поведению (вытеснениям записей) и «плавающим» 429.

Мини-чеклист: как быстро привести nginx 429 в порядок

  1. Убедитесь, что 429 отдаёт именно Nginx (limit_req/limit_conn), а не приложение.
  2. Проверьте реальный IP клиента за reverse proxy: настройте set_real_ip_from, real_ip_header, real_ip_recursive.
  3. Снимите срез по 429: топ источников и топ URI по access log.
  4. Подберите rate и burst под профиль нагрузки: всплески чаще лечатся burst, а не завышением rate.
  5. Решите, нужна ли задержка или «быстрый отказ»: добавлять ли nodelay.
  6. Используйте limit_conn как страховку, но не как единственный механизм защиты.

А чтобы пользователи и интеграции реже повторяли запросы из-за проблем с безопасным соединением и редиректами, заранее проверьте цепочку доменов/сертификатов и HSTS: пригодится материал про миграцию домена, 301, HSTS и SSL. Если нужен сертификат под прод, посмотрите SSL-сертификаты.

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

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

Debian/Ubuntu: mount: wrong fs type, bad option, bad superblock — как быстро найти и исправить причину OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: mount: wrong fs type, bad option, bad superblock — как быстро найти и исправить причину

Ошибка mount: wrong fs type, bad option, bad superblock в Debian/Ubuntu может означать и простую опечатку в имени раздела, и пробл ...
Debian/Ubuntu: XFS metadata corruption и emergency read-only — пошаговое восстановление OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: XFS metadata corruption и emergency read-only — пошаговое восстановление

Если XFS-раздел внезапно стал доступен только для чтения, а сервер ушёл в emergency mode, главное — не спешить. Разберём безопасны ...
Debian/Ubuntu: как исправить Failed to fetch при apt update OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: как исправить Failed to fetch при apt update

Ошибка Failed to fetch при apt update в Debian и Ubuntu обычно связана не с самим APT, а с DNS, сетью, зеркалом, прокси, временем ...