Если у вас есть публичный веб‑сервис, вы рано или поздно столкнётесь со всплесками трафика: анонс в соцсетях, новостное упоминание, наплыв поисковых роботов, «жадные» парсеры или волна повторных запросов из‑за проблем на стороне клиента. В таких ситуациях 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.

Практичные пресеты для типовых сценариев
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.

Тестирование: как убедиться, что не сломали прод
Проверяйте конфиг перед перезагрузкой и используйте 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 минут
- Включите корректный
real_ipи доверяйте только своим прокси/балансировщикам. - Создайте базовые зоны:
limit_req_zoneиlimit_conn_zoneпо IP/ключу. - Примените умеренный профиль к общим локациям и строгий — к «горячим» эндпоинтам.
- Настройте коды 429 и
Retry-After, заведите отдельный лог ограничений. - Проведите нагрузочный тест, проверьте долю 429 и латентность.
- Вынесите пресеты в include‑файл, чтобы быстро подкручивать значения.
Когда стоит пойти дальше
Если всплески регулярные или есть признаки распределённой атаки, комбинируйте лимитирование с кэшем на периметре, фильтрацией по сигнатурам/поведению и масштабированием. Для проектов с высокой интенсивностью трафика переход на VDS даёт изолированные ресурсы и предсказуемую сетевую производительность.
Чтобы выбрать удобную панель для администрирования, пригодится сравнительный обзор: vds-panels-2025-comparison.
Итог: limit_req, limit_conn, burst и корректный real_ip превращают хаотичный трафик в контролируемый. Начните с простых пресетов, включите логи — и доведите баланс между стабильностью и UX.


