Распределённая атака на отказ в обслуживании (DDoS) — это не гипотетическая угроза, а ежедневная реальность для публичных сервисов. В то время как сетевые атаки (L3/L4) требуют защиты на уровне провайдера или аппаратного фаервола, атаки на уровне приложений (L7) часто можно эффективно парировать средствами самого веб-сервера. Nginx, благодаря своим встроенным модулям и гибкой конфигурации, является мощным инструментом для защиты от HTTP-флуда, медленных атак и исчерпания ресурсов.
Это практическое руководство предоставляет готовые, проверенные на продакшн-средах конфигурации для настройки базовой защиты, интеграции с системами мониторинга и автоматизации блокировки атакующих IP. Вы получите пошаговые инструкции по настройке модулей ngx_http_limit_req_module и ngx_http_limit_conn_module, оптимизации таймаутов и буферов, а также развертыванию стека мониторинга Prometheus/Grafana для визуализации атак в реальном времени и настройки fail2ban для автоматического ответа.
Базовые механизмы защиты Nginx: ограничение запросов и подключений
Первая линия обороны Nginx от DDoS на уровне приложения — это встроенные модули для контроля частоты запросов и количества параллельных соединений. Их правильная настройка позволяет отсечь большую часть простого флуда, не затрагивая легитимных пользователей. Основа защиты — разделяемая зона памяти (shared zone), где Nginx хранит счетчики для каждого клиента, определенного по ключу (например, IP-адресу).
Борьба с флудом запросов: настройка limit_req_zone и limit_req
Модуль ngx_http_limit_req_module ограничивает частоту обработки запросов с одного клиента, реализуя алгоритм «ведра» (leaky bucket). Это основное средство против HTTP-флуда, когда атакующий пытается перегрузить сервер большим количеством запросов в секунду.
Настройка выполняется в два этапа: определение зоны в контексте http и ее применение в контекстах server или location.
# В блоке http (nginx.conf или /etc/nginx/nginx.conf)
http {
# Определяем зону limit_req. Ключ - бинарное представление IP клиента.
# Размер зоны 10m (10 мегабайт) может хранить около 160 тысяч состояний.
# Частота (rate) ограничена 10 запросами в секунду с одного IP.
limit_req_zone $binary_remote_addr zone=req_per_ip:10m rate=10r/s;
... # остальные директивы http
server {
listen 80;
server_name example.com;
# Применяем лимит ко всему серверу
limit_req zone=req_per_ip burst=20 nodelay;
location /api/ {
# Более строгий лимит для API
limit_req zone=req_per_ip burst=5 nodelay;
}
location /static/ {
# Для статики лимиты можно не применять или сделать мягче
# limit_req off;
}
}
}
Пояснение ключевых параметров:
limit_req_zone $binary_remote_addr zone=req_per_ip:10m rate=10r/s;: Создает зонуreq_per_ipразмером 10 МБ, где ключом является IP-адрес клиента ($binary_remote_addrзанимает меньше памяти, чем строковый адрес). Лимит скорости (rate) установлен в 10 запросов в секунду (r/s) с одного IP.limit_req zone=req_per_ip burst=20 nodelay;: Применяет созданную зону. Параметрburst=20определяет размер «буфера» или «очереди». Если клиент превышает rate, первые 20 «лишних» запросов будут помещены в очередь и обработаны с задержкой. Параметрnodelayозначает, что запросы в пределах burst будут обработаны без задержки, но как только очередь заполнится, последующие запросы получат ответ503 Service Temporarily Unavailable. Безnodelayзапросы в очереди обрабатывались бы с задержкой, что нежелательно при атаке.
Рекомендации по настройке: Значение rate зависит от логики вашего приложения. Для статических сайтов или API с кешированием можно установить 50-100 r/s. Для ресурсоемких API (генерация отчетов, поиск) стоит ограничить 1-5 r/s. Размер burst должен позволять обработать кратковременные всплески легитимного трафика (например, загрузка страницы с несколькими ресурсами), но быть недостаточным для эффективной атаки. Типичные значения — от 5 до 30.
Контроль параллельных соединений: директива limit_conn
Модуль ngx_http_limit_conn_module ограничивает количество одновременных соединений с одного клиента. Это защищает от атак, направленных на исчерпание лимитов дескрипторов файлов или памяти у воркеров Nginx (например, атака Slowloris, когда множество медленных соединений держится открытыми).
http {
# Определяем зону limit_conn. Ключ - IP.
# Размер зоны 10m.
limit_conn_zone $binary_remote_addr zone=conn_per_ip:10m;
server {
listen 80;
server_name example.com;
# Ограничиваем 20 одновременных соединений с одного IP
limit_conn conn_per_ip 20;
# Дополнительно можно ограничить соединения на сервер (общий лимит)
# limit_conn per_server 1000;
location /download/ {
# Для загрузок можно установить отдельный, более строгий лимит
limit_conn conn_per_ip 5;
}
}
}
При превышении лимита limit_conn новые соединения от этого клиента будут отклоняться с ошибкой. Для большинства веб-приложений 10-20 одновременных соединений с одного IP — разумный лимит, который не затронет обычных пользователей, но остановит простые атаки на исчерпание соединений. Для эффективной защиты от сложных Slow-атак эту настройку необходимо комбинировать с оптимизацией таймаутов, описанной в следующем разделе.
Эти базовые настройки — фундамент защиты. Для комплексного управления трафиком в распределенных системах рассмотрите также настройку алгоритмов балансировки нагрузки в Nginx, что позволяет распределять атакующий трафик между несколькими серверами бэкенда.
Оптимизация производительности под атакой: таймауты и буферы
Настройка лимитов — это активная защита. Оптимизация таймаутов и буферов — это пассивная устойчивость, которая минимизирует ресурсные затраты сервера во время атаки и делает его менее уязвимым к специфическим векторам, таким как Slowloris или атаки на переполнение буферов.
Настройка таймаутов для отсечения медленных атак
Медленные атаки (Slowloris, Slow POST) работают, удерживая соединения открытыми как можно дольше, отправляя данные минимальными порциями. Агрессивные, но разумные таймауты обрывают такие соединения, освобождая ресурсы.
http {
# Таймаут на чтение заголовка запроса от клиента.
# Если клиент не отправил весь заголовок за это время - соединение закрывается.
client_header_timeout 5s;
# Таймаут на чтение тела запроса от клиента.
# Актуально для атак Slow POST.
client_body_timeout 5s;
# Таймаут на передачу ответа клиенту.
# Если клиент не готов принимать данные - соединение закрывается.
send_timeout 10s;
# Время, в течение которого keep-alive соединение с клиентом будет открыто.
keepalive_timeout 30s;
# Максимальное количество запросов, которое можно сделать по одному keep-alive соединению.
keepalive_requests 100;
server {
...
}
}
Значения в 5-10 секунд достаточно для легитимных клиентов даже с нестабильным интернетом, но делают медленную атаку неэффективной. Снижение keepalive_timeout и keepalive_requests ускоряет освобождение соединений, что особенно важно под нагрузкой.
Тюнинг буферов для экономии памяти
Атакующий может попытаться исчерпать оперативную память сервера, отправляя запросы с огромными заголовками или телами. Ограничение размеров буферов предотвращает это.
http {
# Размер буфера для чтения заголовка запроса клиента.
# Для большинства запросов 1К достаточно.
client_header_buffer_size 1k;
# Максимальное количество и размер буферов для больших заголовков.
# Здесь: 4 буфера по 8К каждый.
large_client_header_buffers 4 8k;
# Размер буфера для чтения тела запроса.
# Если тело больше, оно пишется во временный файл.
# Установка слишком малого значения увеличивает нагрузку на диск I/O.
client_body_buffer_size 16k;
# Максимально допустимый размер тела запроса от клиента.
# Запросы больше этого размера получат ошибку 413 (Request Entity Too Large).
# Значение должно соответствовать требованиям приложения (загрузка файлов).
client_max_body_size 10m;
server {
...
}
}
Принцип настройки буферов: устанавливать минимально достаточные для работы вашего приложения значения. Например, если ваш API не принимает большие файлы, client_max_body_size можно установить в 1-2 МБ. Это также защитит от атак, пытающихся загрузить огромные файлы.
После настройки базовой защиты и оптимизации производительности критически важно не оставаться «слепым». Вам нужен инструмент для наблюдения за эффективностью этих мер и масштабом инцидента. Для комплексной диагностики производительности в связке с Nginx также полезно изучить методы диагностики и оптимизации веб-приложений.
Интеграция с Prometheus и Grafana: мониторинг атак в реальном времени
Конфигурация без мониторинга — это «черный ящик». Вы не знаете, срабатывают ли лимиты, сколько запросов отбрасывается и от каких IP. Настройка сбора метрик превращает данные Nginx в наглядные графики и своевременные оповещения.
Настройка сбора метрик Nginx для Prometheus
Есть два основных способа экспорта метрик из Nginx в Prometheus:
- nginx-module-vts (Nginx Virtual Host Traffic Status Module): Модуль, компилируемый в Nginx, предоставляет расширенную статистику по виртуальным хостам, upstream-блокам, кэшам и зонам limit_req/limit_conn. Более полные данные, но требует перекомпиляции Nginx.
- nginx-prometheus-exporter: Отдельный демон (экспортер), который парсит страницу stub_status или JSON-вывод модуля VTS и предоставляет метрики в формате Prometheus. Проще в развертывании, но зависит от доступности данных в основном Nginx.
Рассмотрим вариант с модулем VTS как наиболее информативный. После установки модуля (процесс зависит от ОС и способа сборки Nginx) добавьте в конфигурацию:
http {
# Включаем модуль vts
vhost_traffic_status_zone;
# Опционально: увеличиваем размер зоны сбора данных
# vhost_traffic_status_zone shared:vhost_traffic_status:10m;
... # зоны limit_req, limit_conn и пр.
server {
listen 80;
server_name example.com;
...
}
# Отдельный server-блок для метрик (рекомендуется закрыть доступ)
server {
listen 8080; # Не публичный порт
server_name localhost;
allow 127.0.0.1; # Только localhost
allow 10.0.0.0/8; # И ваша внутренняя сеть
deny all;
location /status {
vhost_traffic_status_display;
vhost_traffic_status_display_format html; # или json
}
# Endpoint для Prometheus в формате JSON
location /status/format/json {
vhost_traffic_status_display;
vhost_traffic_status_display_format json;
}
}
}
После перезагрузки Nginx страница http://your-server:8080/status покажет статистику. Для сбора метрик в Prometheus используйте nginx-prometheus-exporter, настроенный на парсинг JSON с /status/format/json, или соберите метрики напрямую, если экспортер поддерживает VTS. Конфигурация job в prometheus.yml:
scrape_configs:
- job_name: 'nginx'
static_configs:
- targets: ['nginx-exporter-host:9113'] # или адрес Nginx с модулем VTS, если экспортер парсит удаленно
metrics_path: /metrics
scrape_interval: 15s
Ключевые метрики для мониторинга DDoS:
nginx_http_limit_req_delayed/nginx_http_limit_req_rejected: Количество запросов, задержанных и отклоненных из-за срабатыванияlimit_req.nginx_http_limit_conn_active/nginx_http_limit_conn_rejected: Активные и отклоненные соединения из-заlimit_conn.nginx_connections_active/nginx_connections_reading/nginx_connections_writing: Общее состояние соединений.
Дашборд Grafana для визуализации атаки и настройка алертов
Импортируйте готовый дашборд для Nginx (например, ID 2949) или создайте свой. Ключевые панели для отслеживания атак:
- График отброшенных запросов (limit_req_rejected): Резкий рост — явный признак HTTP-флуда.
- График активных соединений (connections_active): Нехарактерно высокое значение может указывать на атаку на исчерпание соединений.
- Топ IP-адресов по количеству отброшенных запросов: Позволяет сразу выявить источники атаки. Строится на основе метрик с лейблами.
- Статус-коды ответов: Рост доли кодов 503 (ограничение) и 499 (клиент закрыл соединение при таймауте).
Для автоматического оповещения настройте правила в Prometheus Alertmanager или в Grafana. Пример правила для Prometheus:
groups:
- name: nginx_ddos
rules:
- alert: NginxHighRejectRate
expr: rate(nginx_http_limit_req_rejected_total[5m]) > 10
for: 2m
labels:
severity: warning
annotations:
summary: "Высокий уровень отклонения запросов в Nginx"
description: "Скорость отклонения запросов limit_req превышает 10 в секунду последние 2 минуты. Возможна DDoS-атака на уровне приложения."
Автоматизация ответа: блокировка атакующих IP с помощью fail2ban
Мониторинг показывает атаку, но блокировать IP вручную — медленно и неэффективно. Fail2ban автоматизирует этот процесс, анализируя логи и добавляя нарушителей в blacklist фаервола.
Создание фильтров fail2ban для логов Nginx
Fail2ban работает по принципу: фильтр (регулярное выражение) находит в логе строку-признак нарушения, счетчик увеличивается. При превышении порога (maxretry) за время (findtime) срабатывает действие (action), например, блокировка IP в iptables.
Создайте фильтр для обнаружения срабатывания limit_req (файл /etc/fail2ban/filter.d/nginx-limit-req.conf):
[Definition]
failregex = ^\[error\] \d+#\d+: \*\d+ limiting requests, excess: [\d\.]+ by zone "[^"]*", client: ,.*$
ignoreregex =
datepattern = ^%%Y/%%m/%%d %%H:%%M:%%S
Создайте фильтр для обнаружения срабатывания limit_conn (файл /etc/fail2ban/filter.d/nginx-limit-conn.conf):
[Definition]
failregex = ^\[error\] \d+#\d+: \*\d+ limiting connections by zone "[^"]*", client: ,.*$
ignoreregex =
datepattern = ^%%Y/%%m/%%d %%H:%%M:%%S
Проверьте работу фильтра командой: fail2ban-regex /var/log/nginx/error.log /etc/fail2ban/filter.d/nginx-limit-req.conf.
Конфигурация jail и блокировка через ipset
Прямое добавление тысяч правил в iptables снижает производительность. Используйте ipset — расширение для эффективного хранения множества IP-адресов в одном правиле фаервола.
Сначала создайте ipset (можно сделать через action fail2ban или заранее):ipset create nginx-blacklist hash:ip timeout 86400
Добавьте правило iptables для блокировки этого набора:iptables -I INPUT -m set --match-set nginx-blacklist src -j DROP
Теперь настройте jail в /etc/fail2ban/jail.local:
[nginx-limit-req]
enabled = true
port = http,https
filter = nginx-limit-req
logpath = /var/log/nginx/error.log
maxretry = 5
findtime = 60
bantime = 3600
action = iptables-ipset-proto6[name=NGINX, port="http,https", protocol=tcp, chain=INPUT, setname=nginx-blacklist]
Пояснение параметров:
maxretry=5: Количество совпадений с фильтром до блокировки.findtime=60: Временное окно (в секундах), в котором учитываются попытки.bantime=3600: Время блокировки IP (в секундах). 3600 = 1 час.action = iptables-ipset-proto6: Действие, использующее ipset. Убедитесь, что этот action доступен в вашей системе.
После перезапуска fail2ban (systemctl restart fail2ban) система начнет автоматически блокировать IP-адреса, которые превышают лимиты запросов, указанные в вашей конфигурации Nginx. Для защиты критически важных API или административных интерфейсов можно настроить более агрессивные правила (меньше maxretry, больше bantime).
Проверка, тестирование и границы возможностей
Любые изменения, особенно связанные с безопасностью и ограничениями, должны быть тщательно протестированы в staging-среде перед выкаткой в продакшн.
Верификация настроек и нагрузочное тестирование
- Проверка синтаксиса: Всегда выполняйте
nginx -tперед перезагрузкой конфигурации. - Тестирование лимитов: Используйте инструменты нагрузочного тестирования для имитации как нормального трафика, так и атаки.
- wrk:
wrk -t12 -c100 -d30s --latency http://your-server/(12 потоков, 100 соединений, 30 секунд). - ab (ApacheBench):
ab -n 1000 -c 50 http://your-server/(1000 запросов, 50 одновременно). - Специализированные утилиты: Для имитации медленных атак можно использовать
slowhttptest.
- wrk:
- Анализ результатов: Во время теста следите:
- За логами Nginx (
tail -f /var/log/nginx/error.log), появятся ли записи «limiting requests». - За метриками в Grafana: растут ли графики
limit_req_rejected. - За ответами сервера: не получают ли легитимные (имитируемые) пользователи ошибки 503.
- За логами Nginx (
Цель теста — убедиться, что при нормальной нагрузке ошибок нет, а при атакующей — лимиты срабатывают и метрики/логи это фиксируют.
Что Nginx не защитит: когда нужны другие решения
Важно понимать границы ответственности конфигурации Nginx:
- Объемные (Volumetric) DDoS-атаки (L3/L4): SYN-flood, UDP-amplification, ICMP-flood. Эти атаки направлены на насыщение полосы пропускания канала или ресурсов сетевого стека ОС. Nginx может даже не получить пакеты. Решение: Защита на уровне сети: аппаратные фаерволы, облачные сервисы защиты (Cloudflare, AWS Shield, GCP Cloud Armor), настройка фильтрации на маршрутизаторе.
- Атаки на уровне приложений (L7), обходящие простые лимиты: Сложные бот-сети, имитирующие поведение человека, или атаки на уязвимости конкретного веб-приложения. Решение: Использование WAF (Web Application Firewall), такого как ModSecurity (есть модуль для Nginx), или облачных WAF-сервисов.
- Атаки на DNS: Nginx здесь бессилен. Решение: Защита DNS-провайдера.
Таким образом, настройки Nginx — это критически важный, но один из слоев многоуровневой защиты. Их следует комбинировать с настройкой сетевого экрана ОС (например, iptables/nftables с правилами против SYN-flood), использованием облачных прокси и поддержанием актуальности ПО. Для обеспечения максимальной доступности ваших сервисов в условиях высокой нагрузки также рекомендуется изучить принципы продвинутой настройки Nginx как балансировщика нагрузки с health checks и отказоустойчивостью. А для безопасного взаимодействия с внешним миром фундаментом является правильная настройка SSL/TLS и HTTPS в Nginx.
Представленные в статье конфигурации, настройки мониторинга и автоматизации блокировок образуют готовый, проверенный на практике комплекс мер для защиты ваших веб-сервисов на Nginx от наиболее распространенных DDoS-атак уровня приложений. Регулярно проверяйте логи и метрики, адаптируйте лимиты под реальную нагрузку вашего сервиса и помните, что безопасность — это непрерывный процесс.