Защита от ботов в Nginx: сравниваем четыре подхода
Одного запрета по User-Agent недостаточно: его легко подделать, а жёсткий лимит может задеть поисковых роботов и обычных пользователей. Сравниваем rate limiting, лимит соединений, фильтры и внешний WAF.

Если бот открывает сотни страниц в секунду, Nginx может начать отдавать 429 раньше, чем приложение упрётся в CPU или базу данных. Но простой запрет по User-Agent почти бесполезен: заголовок подделывается одной строкой. Ниже — четыре подхода для Nginx 1.25.x и критерии выбора, чтобы ограничить мусорный трафик, не сломав поисковую индексацию и мобильную сеть.
Что именно нужно защищать
У ботов разные цели. Одни перебирают URL и создают нагрузку на PHP или API. Другие держат много открытых соединений. Третьи делают редкие, но дорогие запросы: поиск, авторизацию, оформление заказа. Поэтому один лимит на весь сайт редко работает хорошо.
Перед настройкой зафиксируйте три показателя:
- долю ответов 429 и 403 в обычный час;
- URL, которые бот запрашивает чаще всего;
- время ответа upstream и число активных соединений.
Сравнивайте изменения на одинаковом окне времени. Если нет исходных данных, сначала включите расширенный access log и соберите хотя бы несколько часов наблюдений. Придумывать «безопасный» запросов в секунду нельзя: для новостной страницы, каталога и API это будут разные значения.
Хорошая защита от ботов не пытается угадать намерения каждого клиента. Она делает дорогие действия ограниченными и предсказуемыми.
Сноска. Rate limiting — ограничение частоты запросов. В Nginx оно обычно работает по ключу, например по IP-адресу, и хранит счётчики в общей зоне памяти.
Четыре подхода и их цена
| Подход | Что блокирует | Плюс | Цена и риск |
|---|---|---|---|
| Лимит запросов | Слишком частые обращения | Работает на уровне Nginx, не требует приложения | Общий IP может принадлежать десяткам пользователей |
| Лимит соединений | Большое число одновременных соединений | Сдерживает медленных клиентов и всплески | Не отличает бота от легитимного клиента |
| Фильтр User-Agent и IP | Известные или явно поддельные признаки | Простая точечная блокировка | Заголовок подделывается, списки быстро устаревают |
| Внешний WAF или CDN | Ботов до origin-сервера, включая поведенческие сценарии | Челленджи, репутация IP и масштабирование на edge | Платная услуга, зависимость от DNS и корректной передачи IP |
На практике базовая связка для большинства сайтов — лимит запросов плюс лимит соединений. Фильтры добавляют для конкретных известных источников. WAF нужен, когда атака уже съедает канал, балансировщик или заметную часть счёта за инфраструктуру.
Подход 1. Лимит запросов через limit_req
Модуль ngx_http_limit_req_module ограничивает скорость обращений по ключу. Для публичного сайта чаще всего начинают с IP, но за прокси это значение нужно настроить особенно внимательно: без корректного real IP весь трафик может выглядеть как один адрес.
Зону объявляют в контексте http, а применяют в server или location. Ниже — рабочий фрагмент для Nginx 1.25.x: средняя скорость — пять запросов в секунду на IP, ещё двадцать запросов временно помещаются в очередь.
http {
limit_req_zone $binary_remote_addr zone=per_ip:10m rate=5r/s;
server {
listen 80;
server_name example.com;
location / {
limit_req zone=per_ip burst=20 nodelay;
limit_req_status 429;
proxy_pass http://application;
}
}
}
С параметром nodelay запросы из допустимого burst проходят сразу, пока не исчерпан запас. Без него Nginx будет растягивать обработку очереди, что уменьшает резкий всплеск, но увеличивает задержку.
Проверка результата: в access log должны появиться ответы 429 при превышении лимита, а легитимный запрос к обычной странице должен по-прежнему доходить до upstream. Не применяйте один и тот же жёсткий лимит к HTML, изображениям и поисковому API: статика и дорогие операции создают разную нагрузку.
Как выбрать ключ
IP — безопасная отправная точка, но в офисе, вузе или мобильной сети один адрес может быть общим. Идентификатор пользователя подходит только для авторизованных запросов и требует отдельного поведения для анонимных клиентов. Ограничение по URL полезно для поиска, входа и API, где запрос дороже просмотра страницы.
Подход 2. Лимит одновременных соединений
limit_conn решает другую задачу: он ограничивает количество одновременно обрабатываемых соединений по ключу. Это не замена rate limiting. Бот может делать один новый запрос после каждого ответа и не превышать лимит соединений, но всё равно создать высокую частоту обращений.
http {
limit_conn_zone $binary_remote_addr zone=per_ip_conn:10m;
server {
listen 80;
server_name example.com;
location /api/ {
limit_conn per_ip_conn 20;
limit_conn_status 429;
proxy_pass http://application;
}
}
}
Такой лимит полезен для медленных клиентов, длинных запросов и API с потоковой выдачей. Число 20 — пример, а не универсальная рекомендация: его нужно сопоставить с лимитами upstream, размером worker_connections и фактическим временем ответа.
Подход 3. Фильтры по User-Agent и адресу
Фильтр подходит для точечной реакции: например, вы уже видите конкретный вредоносный User-Agent или адрес, который не должен обращаться к закрытому endpoint. Для этого достаточно map в контексте http и безопасного для Nginx условия с возвратом ответа.
http {
map $http_user_agent $blocked_client {
default 0;
~*"bad-crawler" 1;
}
server {
listen 80;
server_name example.com;
location / {
if ($blocked_client) {
return 403;
}
proxy_pass http://application;
}
}
}
Конструкция с if в Nginx имеет ограничения, но проверка условия и немедленный return — один из предусмотренных безопасных сценариев. Не превращайте этот блок в набор сложных переписываний.
Главная проблема подхода — подмена заголовка. Настоящий поисковый робот тоже может попасть под грубое правило, а новый вредоносный клиент легко сменит строку. Списки User-Agent и IP используйте как временную заплатку, а не как систему распознавания ботов.
Подход 4. Внешний WAF или CDN
Если мусорный трафик забивает канал до Nginx, локальный лимит срабатывает слишком поздно: запрос уже дошёл до вашей инфраструктуры. Внешний WAF или CDN может отфильтровать часть обращений на edge-узлах, применить репутацию IP, cookie-челленджи и отдельные правила для API.
Цена — подписка, дополнительная точка отказа и необходимость правильно передавать реальный адрес клиента. Нельзя бездумно доверять заголовку X-Forwarded-For: принимать его как источник IP следует только от известных прокси, перечисленных в настройках модуля realip. Точная схема зависит от выбранного провайдера и его документации.
Что выбрать в типичных сценариях
Небольшой сайт или блог
Начните с limit_req для динамических страниц и отдельного, более мягкого правила для API. Добавьте limit_conn, если наблюдаются зависшие соединения. User-Agent используйте только для явных повторяющихся источников.
Интернет-магазин
Не ставьте жёсткий общий лимит на весь каталог: пользователи и поисковые роботы ходят по множеству страниц, а общий NAT скрывает их за одним IP. Отдельно ограничьте поиск, авторизацию, корзину и оформление заказа. Ошибка в этих лимитах стоит дороже, чем несколько лишних запросов: покупатель увидит 429 в момент оплаты.
API
Лимитируйте по API-ключу или аккаунту, если такая идентификация уже есть, а для анонимных запросов оставьте IP-ограничение. Учитывайте стоимость операций: запрос с простым чтением и тяжёлый полнотекстовый поиск не должны автоматически получать одинаковый бюджет.
Что ломается чаще всего
- Все пользователи получают 429. Проверьте, не видит ли Nginx адрес балансировщика вместо клиента. Исправляйте цепочку real IP только для доверенных прокси.
- Лимит не влияет на нагрузку. Возможно, правило стоит после маршрутизации, а тяжёлый endpoint обслуживается другим
location. Проверьте фактический URI и порядок выбора location. - Поисковая индексация просела. Посмотрите ответы 429 и 403 по User-Agent и IP. Не разрешайте роботов только по строке User-Agent без дополнительных ограничений.
- Медленные клиенты продолжают занимать workers. Добавьте ограничение соединений и отдельно проверьте таймауты proxy.
limit_reqне решает проблему долгого соединения сам по себе. - Правило не загружается. Перед reload проверяйте конфигурацию командой
nginx -tв окружении, где установлен ваш Nginx. Если директива неизвестна, проверьте, собран ли нужный модуль и совпадает ли версия документации.
Когда что выбирать
Выбирайте limit_req, когда проблема измеряется частотой запросов. Добавляйте limit_conn, когда проблема — в параллельных или долго живущих соединениях. Используйте фильтр по User-Agent или IP только для локальной блокировки конкретного источника. Переходите к WAF, если трафик нужно отсеивать до origin-сервера или атака меняет адреса и заголовки быстрее, чем вы обновляете конфигурацию.
Не пытайтесь решить инвалидацию кеша, проверку поисковых роботов и защиту формы одной директивой Nginx — это отдельные задачи.
Что настроить дальше
Сначала включите наблюдение за статусами 429, временем ответа upstream и числом активных соединений. Затем задайте мягкий лимит только для самого дорогого endpoint и поднимайте строгость по данным, а не по ощущениям. После каждого изменения проверяйте каталог, авторизацию, поиск и оплату с обычного IP, через мобильную сеть и через ваш реальный прокси-слой.
Помощник по курсовой и диплому: Большая работа поэтапно: от плана до защиты
Спросить за 25 ₽Источники: Nginx documentation: ngx_http_limit_req_module, Nginx documentation: ngx_http_limit_conn_module
Частые вопросы
Достаточно ли запретить ботов по User-Agent?
Какой лимит запросов поставить на сайт?
Почему после включения limit_req 429 получают обычные пользователи?
Можно ли защитить Nginx от атаки, если она забивает канал?
Что лучше использовать: limit_req или limit_conn?
Может ли лимит сломать поисковую индексацию?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.