
Сервер без защиты от DDoS ложится при первой же серьёзной атаке. Полную защиту от объёмных атак (10+ Gbps) даёт только CDN или специализированный scrubbing-центр, но от прикладных атак (HTTP-flood, slowloris, SYN-flood) можно защититься на уровне самого сервера. Разберём трёхуровневую защиту: iptables на сетевом уровне, nginx на уровне приложения и fail2ban для автоматической блокировки.
Уровни защиты
Атаки бывают разных типов, и каждый требует своего инструмента:
Объёмные атаки (volumetric) - UDP flood, ICMP flood, заполнение канала. Против них помогает только CDN (Cloudflare, DDoS-Guard) или BGP-anycast. Сервер здесь бессилен.
SYN flood - полуоткрытые TCP-соединения, переполнение очереди. Защита: iptables + sysctl.
Connection flood - тысячи реальных TCP-соединений. Защита: iptables limit, nginx
limit_conn.HTTP-flood - легитимные HTTP-запросы с высокой частотой. Защита: nginx
limit_req, fail2ban.Slowloris - медленная отправка заголовков, удержание соединений. Защита:
client_header_timeoutв nginx.
Первая линия: CDN
До настройки сервера - важный шаг. Поставьте DNS за Cloudflare (бесплатный план) или DDoS-Guard. Тогда реальный IP сервера скрыт, и объёмные атаки поглощает CDN.
Проверка, не утёк ли реальный IP:
# Ищем IP в исторических DNS-записях
# Проверяем MX-записи - часто раскрывают реальный IP
dig MX yourdomain.com
Если IP уже известен атакующим - смените его у хостера.
Защита iptables от SYN-flood и connection flood
Настройка sysctl для TCP
sudo nano /etc/sysctl.conf
Добавляем:
# SYN cookies - защита от SYN flood
net.ipv4.tcp_syncookies = 1
# Уменьшаем время ожидания для полуоткрытых соединений
net.ipv4.tcp_syn_retries = 3
net.ipv4.tcp_synack_retries = 2
# Размер очереди для входящих соединений
net.ipv4.tcp_max_syn_backlog = 4096
net.core.somaxconn = 4096
# Защита от спуфинга
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
# Игнорировать ICMP broadcast (Smurf attack)
net.ipv4.icmp_echo_ignore_broadcasts = 1
Применяем:
sudo sysctl -pПравила iptables
# Ограничение новых соединений - не более 20 новых TCP в секунду с одного IP
sudo iptables -A INPUT -p tcp --syn -m limit --limit 20/s --limit-burst 50 -j ACCEPT
sudo iptables -A INPUT -p tcp --syn -j DROP
# Ограничение числа одновременных соединений с одного IP (max 50)
sudo iptables -A INPUT -p tcp --dport 80 -m connlimit --connlimit-above 50 -j REJECT --reject-with tcp-reset
sudo iptables -A INPUT -p tcp --dport 443 -m connlimit --connlimit-above 50 -j REJECT --reject-with tcp-reset
# Блокировка INVALID-пакетов
sudo iptables -A INPUT -m state --state INVALID -j DROP
# Ограничение ICMP (пинг) - не более 1 в секунду
sudo iptables -A INPUT -p icmp --icmp-type echo-request -m limit --limit 1/s -j ACCEPT
sudo iptables -A INPUT -p icmp --icmp-type echo-request -j DROP
# Защита SSH от брутфорса - не более 4 попыток в минуту
sudo iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --set
sudo iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 4 -j DROP
Сохраняем правила:
sudo apt install iptables-persistent -y
sudo netfilter-persistent save

Защита на уровне Nginx
limit_req - ограничение частоты запросов
Директива limit_req_zone определяет зону ограничения в блоке http:
http {
# Зона для ограничения запросов: ключ - IP, память - 10 МБ, лимит - 10 req/s
limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s;
# Зона для API - строже
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=2r/s;
# Логировать превышения как warning, не error
limit_req_log_level warn;
# Код ответа при превышении (429 = Too Many Requests)
limit_req_status 429;
}
В блоке server или location:
server {
listen 80;
server_name example.com;
# Применяем к всему сайту
limit_req zone=req_limit burst=20 nodelay;
location /api/ {
limit_req zone=api_limit burst=5;
proxy_pass http://backend;
}
location /wp-login.php {
limit_req zone=api_limit burst=2 nodelay;
# Или сразу закрыть для всех, кроме вашего IP
allow 1.2.3.4;
deny all;
}
}
Параметры burst и nodelay:
burst=20- разрешает кратковременный пик до 20 запросов сверх лимитаnodelay- обрабатывает burst сразу, без задержки; без этого nginx добавляет задержку
limit_conn - ограничение числа соединений
http {
# Зона для ограничения соединений
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
limit_conn_status 503;
}
server {
# Не более 20 одновременных соединений с одного IP
limit_conn conn_limit 20;
}Защита от Slowloris
server {
# Таймауты для предотвращения Slowloris
client_header_timeout 10s;
client_body_timeout 10s;
send_timeout 10s;
# Максимальный размер тела запроса
client_max_body_size 10m;
# Keepalive - ограничиваем время и количество запросов
keepalive_timeout 65s;
keepalive_requests 100;
}Блокировка по User-Agent и заголовкам
# Блокировка пустых User-Agent (характерно для ботов)
if ($http_user_agent = "") {
return 444;
}
# Блокировка известных ботов-атакующих
map $http_user_agent $bad_bot {
default 0;
~*python-requests 1;
~*zgrab 1;
~*masscan 1;
~*nikto 1;
}
server {
if ($bad_bot) {
return 444; # 444 - nginx закрывает соединение без ответа
}
}

Fail2ban для HTTP-flood
Fail2ban анализирует логи и блокирует IP через iptables при превышении порогов.
Установка
sudo apt install fail2ban -y
sudo systemctl enable fail2banJail для nginx
Создаём файл /etc/fail2ban/jail.d/nginx.conf:
[nginx-http-auth]
enabled = true
port = http,https
logpath = /var/log/nginx/error.log
maxretry = 3
bantime = 3600
[nginx-limit-req]
enabled = true
port = http,https
logpath = /var/log/nginx/error.log
maxretry = 10
findtime = 60
bantime = 600
filter = nginx-limit-req
[nginx-botsearch]
enabled = true
port = http,https
logpath = /var/log/nginx/access.log
maxretry = 2
findtime = 60
bantime = 86400
filter = nginx-botsearch
Фильтр для limit_req - /etc/fail2ban/filter.d/nginx-limit-req.conf:
[Definition]
failregex = limiting requests, excess:.* by zone .*, client: <HOST>
ignoreregex =
Фильтр для поиска ботов - /etc/fail2ban/filter.d/nginx-botsearch.conf:
[Definition]
failregex = ^<HOST> -.*"(GET|POST).*(\.php|\.asp|\.env|\.git).*" (404|444|403)
ignoreregex =
Перезапуск и проверка:
sudo systemctl restart fail2ban
sudo fail2ban-client status
sudo fail2ban-client status nginx-limit-req
Ручная блокировка IP:
sudo fail2ban-client set nginx-limit-req banip 1.2.3.4
Ручная разблокировка:
sudo fail2ban-client set nginx-limit-req unbanip 1.2.3.4Мониторинг во время атаки
Посмотреть топ IP по числу запросов:
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20
Текущие соединения по IP:
ss -tn | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -rn | head -20
Число SYN_RECV (признак SYN flood):
ss -s | grep SYN
# или
cat /proc/net/tcp | awk '$4 == "02"' | wc -l
Заблокированные IP в iptables:
sudo iptables -L -n | grep DROP | wc -l

Итог
Трёхуровневая защита: sysctl + iptables блокируют атаки на уровне TCP, nginx limit_req и limit_conn отсекают HTTP-flood до попадания в приложение, fail2ban автоматически банит злоупотребляющие IP по данным из логов. Для WordPress и API устанавливайте лимиты строже, чем для обычного контента. Главный принцип - чем раньше по стеку отклоняется атакующий трафик, тем меньше нагрузка на сервер.