DDoS-атаки (Distributed Denial of Service) перегружают сервер огромным количеством запросов, делая его недоступным для обычных посетителей. Эффективная защита строится на нескольких уровнях: сетевой (Cloudflare/CDN), системный (sysctl) и уровень приложения (Nginx) — ни один слой в одиночку не закрывает все сценарии атаки.
Уровень 1: Cloudflare DDoS Protection (рекомендуется)
Cloudflare поглощает DDoS-трафик до достижения вашего сервера, потому что весь трафик идёт через её сеть точек присутствия:
- Включить Proxy (оранжевое облако) для DNS-записей A и CNAME — без этого Cloudflare видит только DNS-запросы, а сам трафик идёт напрямую на сервер.
- Security → DDoS → включить HTTP DDoS Attack Protection.
- Security → WAF → включить Managed Rules.
- Security Level: High при атаке, Medium в обычном режиме.
Уровень 2: Nginx — ограничения соединений (в дополнение к UFW Firewall)
http {
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
limit_req_zone $binary_remote_addr zone=req_limit:10m rate=50r/s;
server {
limit_conn conn_limit 20; # Макс 20 соединений с одного IP
limit_req zone=req_limit burst=100 nodelay;
limit_req_status 429;
# Таймауты для защиты от Slowloris
client_body_timeout 10;
client_header_timeout 10;
keepalive_timeout 5;
send_timeout 10;
}
}
Уровень 3: Системная оптимизация (sysctl)
# /etc/sysctl.d/99-ddos-protect.conf
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 5
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_keepalive_time = 300
net.ipv4.conf.all.rp_filter = 1
sysctl --system
Разбор сигналов атаки в логах
- 499 в логе Nginx — клиент оборвал соединение, не дождавшись ответа; массовый всплеск 499 говорит о SYN-флуде или переполненной очереди воркеров, а не о медленном приложении.
- upstream timed out (110: Connection timed out) — при атаке уровня приложения (L7) воркеры PHP-FPM заняты обработкой поддельных запросов и не успевают отвечать реальным пользователям.
- too many open files в dmesg или логе Nginx — исчерпан лимит файловых дескрипторов из-за тысяч одновременных соединений; временная мера — поднять
ulimit -n, но это не устраняет саму атаку. - Resource temporarily unavailable (11: Resource temporarily unavailable) при accept() — очередь новых соединений переполнена, сервер физически не успевает принимать новые сокеты быстрее, чем их создаёт атакующий.
Реагирование на атаку
netstat -tn | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -rn | head -20
ss -s
# Быстро заблокировать атакующий IP
iptables -I INPUT -s ATTACK_IP -j DROP
# Включить режим "Under Attack" в Cloudflare
# Security → Settings → Security Level: I'm Under Attack
IP-скрытие за Cloudflare: убедитесь, что реальный IP сервера не раскрывается через DNS-историю, email-заголовки или другие каналы. Cloudflare эффективен только пока атакующий не знает реальный IP и не может обстреливать его напрямую, минуя защиту.
Сравнение уровней защиты
| Уровень | От чего защищает | Где настраивается | Требует ли перезагрузки сервера |
|---|---|---|---|
| Cloudflare | Объёмные (L3/L4) и часть L7-атак | Дашборд Cloudflare | Нет |
| Nginx | L7: флуд запросами к одному URL | Конфиг виртуального хоста | Нет (reload) |
| sysctl | L4: SYN-флуд, исчерпание сокетов | Ядро ОС | Нет (sysctl --system) |
Когда этого набора мер недостаточно
- Атака идёт напрямую на IP сервера, минуя Cloudflare, — если IP утёк раньше, DNS-проксирование не спасёт; нужно менять IP и держать его в секрете, либо переносить сервер в защищённую сеть провайдера.
- Атака объёмом в сотни гигабит в секунду — канал самого сервера физически не пропустит такой трафик даже с идеальными правилами Nginx; здесь решает только upstream-фильтрация на стороне провайдера или CDN.
- Атака имитирует реальных пользователей через ротацию residential-прокси — простой лимит по IP не отличит их от живых людей; нужны поведенческие правила WAF и капча на подозрительных сессиях.
Как проверить, что защита работает
# Смотрим, что запросы реально доходят до Cloudflare, а не в обход
dig +short example.com
# Ожидаем IP из диапазонов Cloudflare, а не IP вашего сервера
# Проверяем срабатывание rate limit на самом Nginx
for i in $(seq 1 60); do curl -o /dev/null -s -w "%{http_code}\n" https://example.com/; done | sort | uniq -c
# Проверяем sysctl-параметры применились
sysctl net.ipv4.tcp_syncookies
Если DNS отдаёт IP из диапазона Cloudflare, часть запросов при нагрузочном тесте возвращает 429, а sysctl-параметры показывают выставленные значения — все три уровня защиты работают согласованно.