[Из песочницы] Оперативная реакция на DDoS-атаки
Один из ресурсов, за которым я присматриваю, вдруг стал неожиданно популярным как у хороших пользователей, так и у плохих. Мощное, в общем-то, железо перестало справляться с нагрузкой. Софт на сервере самый обычный — Linux, Nginx, PHP-FPM (+APC), MySQL, версии — самые последние. На сайтах крутится Drupal и phpBB. Оптимизация на уровне софта (memcached, индексы в базе, где их не хватало) чуть помогла, но кардинально проблему не решила. А проблема — большое количество запросов, к статике, динамике и особенно базе. Поставил следующие лимиты в Nginx: на соединенияlimit_conn_zone $binary_remote_addr zone=perip:10m; limit_conn perip 100; и скорость запросов на динамику (fastcgi_pass на php-fpm)limit_req_zone $binary_remote_addr zone=dynamic:10m rate=2r/s; limit_req zone=dynamic burst=10 nodelay; Сильно полегчало, по логам видно, что в первую зону никто не попадает, зато вторая отрабатывает по полной. Но плохиши продолжали долбить, и захотелось их отбрасывать раньше — на уровне фаервола, и надолго. Сначала сам парсил логи, и особо настырных добавлял через iptables в баню. Потом парсил уже по крону каждые 5 минут. Пробовал fail2ban. Когда понял, что плохишей стало очень много, перенёс их в ipset ip hash. Почти всё хорошо стало, но есть неприятные моменты: — парсинг/сортировка логов тоже приличное (процессорное) время отнимает — сервер тупит, если началась новая волна между соседними разборками (логов) Нужно было придумать как быстро добавлять нарушителей в черный список. Сначала была идея написать/дописать модуль к Nginx + демон, который будет ipset-ы обновлять. Можно и без демона, но тогда придётся запускать Nginx от рута, что не есть красиво. Написать это реально, но понял, что нет столько времени. Ничего похожего не нашёл (может плохо искал?), и придумал вот такой алгоритм. При привышении лимита, Nginx выбрасывает 503-юю ошибку Service Temporarily Unavailable. Вот я решил на неё и прицепиться! Для каждого location создаём свою страничку с ошибкойerror_page 503 =429 @blacklist; И соответствующий именованный locationlocation @blacklist { fastcgi_pass localhost:1234; fastcgi_param SCRIPT_FILENAME /data/web/cgi/blacklist.sh; include fastcgi_params; } Дальше интересней. Нам нужна поддержка CGI-скриптов. Ставим, настраиваем, запускаем spawn-fcgi и fcgiwrap. У меня уже было готовое для collectd. Сам CGI-скриптЧитать дальше →