Руководства

Как защитить сервер от DDoS и пережить всплески трафика

Как защитить сервер от DDoS и пережить всплески трафика

Слова «защита от DDoS» на витринах хостингов звучат как решение всех проблем, но закрывают только один класс атак. Сервер падает не только от гигабитных потоков мусора, но и от сотни запросов в секунду к странице поиска — и от этого никакая сетевая фильтрация не спасёт. Разберём, какие бывают атаки, что закрывает дата-центр, что остаётся на вас, и как настроить сервер так, чтобы он пережил и атаку, и честный всплеск посещаемости после рекламы.

Два класса атак

Объёмные (L3/L4)

На сервер льют поток мусорного трафика — UDP-пакеты, SYN-флуд, отражённые DNS- и NTP-ответы, — чтобы забить канал или исчерпать таблицу соединений. Счёт идёт на гигабиты и миллионы пакетов в секунду. Сервер здесь бессилен: если канал забит до вашей машины, никакая её настройка не поможет. Защищаться от таких атак может только сеть — провайдер, дата-центр или внешний фильтрующий сервис.

Прикладные (L7)

Атака выглядит как обычные запросы к сайту. Тысяча запросов в секунду к поиску, к корзине, к форме восстановления пароля — к любой странице, которая каждый раз лезет в базу. Трафика мало, пакеты легитимные, для сетевого фильтра это просто посетители. А сервер лежит, потому что каждый такой запрос стоит 50–200 мс процессорного времени и десятки обращений к базе.

На практике небольшие и средние проекты гораздо чаще сталкиваются со вторым классом: он дешевле для атакующего и не требует ботнета — хватает пары арендованных машин и скрипта. Хорошая новость: от него вы защищаетесь сами, и это бесплатно.

Что закрывает дата-центр

Большинство дата-центров фильтрует объёмные атаки на уровне сети: аномальный трафик отбрасывается до того, как дойдёт до виртуальной машины, и никаких настроек с вашей стороны не требует. Для этого нужны широкие каналы площадки — фильтрующей системе есть где принять и отбросить лишнее. Какие именно атаки и до какого объёма фильтруются на конкретной площадке, лучше уточнить в поддержке провайдера до того, как это станет срочным.

Если проект в конфликтной нише — игровые серверы, конкурентная e-commerce, политика, криптовалюта — и атаки уже случались, базовой фильтрации может не хватить. Тогда нужен внешний сервис: прокси с фильтрацией вроде Cloudflare (есть бесплатный тариф, закрывающий большую часть L3/L4 и базовый L7) или специализированная защита с выделенным IP.

Что остаётся на вас: пять мер против L7

1. Ограничение частоты запросов

Nginx умеет считать запросы с одного адреса и отвечать ошибкой 429 тем, кто превышает порог. В блоке http:

limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=heavy:10m rate=1r/s;

И в конфигурации сайта:

location / {
    limit_req zone=general burst=20 nodelay;
    ...
}
location ~ ^/(search|login|wp-login\.php|cart) {
    limit_req zone=heavy burst=5;
    ...
}

Десять запросов в секунду с одного IP — много для человека и мало для скрипта. Тяжёлые страницы получают отдельный, более строгий лимит. Проверьте, что не отрезали легитимных пользователей за общим NAT, например из офиса или мобильного оператора, — при необходимости поднимите burst.

2. Ограничение числа соединений

limit_conn_zone $binary_remote_addr zone=addr:10m;
limit_conn addr 20;

Не больше 20 одновременных соединений с одного адреса. Защищает от медленных атак вроде Slowloris, которые держат соединения открытыми, исчерпывая пул рабочих процессов.

3. Кэширование

Главная мера, и против атак, и против всплесков. Страница, отданная из кэша Nginx, стоит микросекунды и не трогает ни PHP, ни базу. Для WordPress и других CMS fastcgi_cache на 1–5 минут для анонимных посетителей снимает 80–95% нагрузки; атака на главную или каталог становится незаметной. Кэш не спасёт страницы, которые по определению динамические — поиск, корзина, личный кабинет, — поэтому для них и нужны лимиты из пункта 1.

4. Блокировка по поведению

fail2ban читает логи и блокирует адреса, которые ведут себя как атака: много ошибок 404 подряд, частые обращения к wp-login.php, превышение лимитов Nginx. Базовая установка — apt install fail2ban, дальше включаются готовые фильтры nginx-limit-req, nginx-botsearch, sshd. Блокировка происходит на уровне firewall, то есть заблокированный адрес вообще перестаёт доходить до веб-сервера.

5. Капча на дорогих операциях

Регистрация, восстановление пароля, отправка форм, поиск — всё, что запускает тяжёлую логику или письмо. Невидимая капча почти не мешает людям и полностью останавливает скрипты.

Атака или просто много посетителей

Внешне всё одинаково: сайт тормозит, процессор в потолке. Разница в логах.

awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

Если сверху десяток адресов с тысячами запросов каждый — это атака или агрессивный бот, и помогут лимиты и блокировка. Если запросы равномерно распределены по тысячам адресов и идут на разные страницы — это честный всплеск, например после рекламы или публикации в крупном канале. Тогда блокировать нечего, нужен кэш и, возможно, ресурсы.

Посмотреть, на какие страницы идёт нагрузка:

awk '{print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

Как понять, что пора увеличить тариф

Защита и кэш не решают проблему, если серверу реально не хватает ресурсов для честной нагрузки. Три сигнала:

  • Память: free -m показывает активно используемый swap. Система вытесняет данные на диск, и дальше тормозит всё. Это первый параметр для апгрейда.
  • Процессор: load average выше числа ядер часами, а не минутами. Разовые пики нормальны, постоянная очередь — нет.
  • Диск: в top показатель wa (ожидание ввода-вывода) устойчиво выше 10–20%. Узкое место в хранилище; на NVMe это встречается заметно реже, чем на SSD.

Если упираетесь в диск — переезжайте в локацию с NVMe: Финляндия, Нидерланды, Чехия. Если в процессор на однопоточных задачах — HI-CPU на Ryzen. Если в память — просто следующий тариф: переход без переноса данных. Как считать, сколько нужно, — в статье «Как выбрать тариф VPS»; когда пора уже на физический сервер — в разборе «VPS или выделенный сервер».

Medium в Финляндии, NVMe — $20/мес   Medium в Нидерландах, NVMe — $20/мес

Что сделать заранее

  1. Включить кэширование для анонимных посетителей.
  2. Настроить limit_req и limit_conn в Nginx, строже — на тяжёлых страницах.
  3. Поставить fail2ban с фильтрами для Nginx и SSH.
  4. Закрыть всё лишнее в firewall: наружу только 80, 443 и SSH.
  5. Уточнить у провайдера, что фильтруется на уровне сети.
  6. Настроить мониторинг с уведомлением — узнать об атаке через минуту, а не через час.
  7. Если проект в рискованной нише — заранее подключить Cloudflare или аналог: во время атаки переключать DNS уже поздно, записи обновляются минутами и часами.

Если сайт всё-таки упал — порядок диагностики в статье «Что делать, если сайт упал».