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 показують виставлені значення — усі три рівні захисту працюють узгоджено.