Fail2ban: продвинутая защита VPS от брутфорса
Базовая настройка SSH-джейла закрывает самый частый случай перебора паролей. Здесь пойдём дальше: свои джейлы, фильтры под конкретные сервисы и разбор действий, если Fail2ban забанил не того.
Что уже настроено
В гайде по базовой защите SSH мы уже включили джейл sshd — Fail2ban читает /var/log/auth.log, считает неудачные попытки входа и банит IP через iptables. Для одиночного сервера с закрытым SSH-паролем этого часто достаточно.
Но Fail2ban — это не только про SSH. Ниже — что стоит добавить, если на сервере крутится сайт за Nginx, своё веб-приложение с логом авторизации, или если один пропущенный лог-файл после ротации внезапно всё ломает.
Как устроены джейлы и фильтры
У Fail2ban три ключевых места, где всё описано:
/etc/fail2ban/filter.d/ — regex-фильтры: как вытащить IP из строки лога
/var/log/fail2ban.log — свой лог демона: кто, когда и почему забанен
Джейл — это связка «какой лог читать» + «каким фильтром искать нарушения» + «что делать при срабатывании». Фильтр — это regex-шаблон с именем группы <HOST>, которая должна совпасть с IP-адресом в строке лога. Настройки лучше держать в jail.local, а не в jail.conf — этот файл могут перезаписать при обновлении пакета.
Джейл для Nginx
Боты и сканеры перебирают пути вида /wp-admin, /.env, /phpmyadmin — их не существует на сервере, но запросы всё равно грузят Nginx и попадают в access.log. Готовый фильтр nginx-botsearch уже входит в поставку Fail2ban и ищет частые 404/403 от одного IP.
Добавляем секцию:
enabled = true
port = http,https
filter = nginx-botsearch
logpath = /var/log/nginx/access.log
maxretry = 10
findtime = 600
bantime = 3600
Если нужен свой критерий — например банить за частые 403 на конкретной локации — можно написать собственный фильтр в /etc/fail2ban/filter.d/nginx-403.conf:
failregex = ^<HOST> -.*"(GET|POST).*" 403
И включаем его в jail.local так же, как nginx-botsearch, указав filter = nginx-403.
Свой фильтр по логам приложения
Если веб-приложение ведёт собственный лог авторизации, Fail2ban можно натравить прямо на него — не обязательно ограничиваться системными логами. Допустим, приложение при неудачном входе пишет в /var/www/app/logs/auth.log строку вида:
Создаём фильтр:
failregex = ^.*Invalid login attempt from <HOST>
ignoreregex =
И джейл в jail.local:
enabled = true
filter = app-auth
logpath = /var/www/app/logs/auth.log
maxretry = 5
findtime = 600
bantime = 1800
action = iptables-allports
fail2ban-regex /var/www/app/logs/auth.log /etc/fail2ban/filter.d/app-auth.conf. Слишком узкий regex не забанит вообще никого, а слишком широкий может зацепить чужие IP из строк, где адрес встречается не как источник атаки — например из заголовка X-Forwarded-For внутри чужого запроса. Ошибка в обе стороны обесценивает джейл или превращает его в оружие против случайных пользователей.Время бана и рецидивисты
Три базовых параметра управляют строгостью джейла:
findtime = 600 # за какой промежуток времени (секунды)
bantime = 1800 # на сколько банить (секунды)
То есть 5 попыток за 10 минут — бан на 30 минут. Для тех, кто возвращается снова и снова, есть эскалация — каждый повторный бан того же IP увеличивается:
bantime.rndtime = 30m
bantime.maxtime = 1w
bantime.factor = 2
bantime.factor умножает срок бана при каждом повторном нарушении (30 минут → час → два часа и так далее, до bantime.maxtime), а bantime.rndtime добавляет случайный разброс, чтобы бот не мог точно рассчитать момент снятия бана.
Просмотр и снятие бана
Посмотреть состояние конкретного джейла — сколько банов активно сейчас и какие IP:
Список всех джейлов:
Снять бан с адреса — например, если под бан случайно попал ваш собственный IP:
Если доступ по SSH уже потерян и подключиться нельзя, эту же команду выполняют через веб-консоль (VNC/serial console) в панели провайдера — она не зависит от сетевого доступа, который как раз заблокирован.
Оповещения о банах
Чтобы не заходить на сервер и не проверять fail2ban-client status вручную, можно настроить письмо при каждом бане. В jail.local в секции [DEFAULT]:
sender = fail2ban@yourserver.ru
action = %(action_mw)s
action_mw — встроенный шаблон «забанить + отправить письмо с whois-информацией по IP». Для этого на сервере должен быть настроен локальный MTA (например postfix) или внешний relay. Вместо почты можно дёрнуть webhook собственным скриптом — action допускает произвольную команду при бане и разбане, но для большинства VPS почтового оповещения достаточно.
Типовые ошибки
- Фильтр написан, но не банит никого — regex не совпадает со строками реального лога; проверяйте через
fail2ban-regex <лог> <фильтр>перед тем, как включать джейл в бою. - Правки в
jail.localилиfilter.d/*.confне применились — конфиг меняется на диске, а демон продолжает работать со старым, пока не выполнитьsudo systemctl restart fail2ban. - Забанили сами себя и потеряли доступ по SSH — снимается через
fail2ban-client unbanipс другого IP или через веб-консоль провайдера; на время отладки нового джейла полезно добавить свой рабочий IP вignoreip. - Логи ротируются logrotate, путь меняется на
.1или архивируется — джейл продолжает следить за уже переименованным файлом и перестаёт видеть новые строки; после смены пути приложения проверяйте актуальностьlogpath. - Джейл включён, но забыли добавить порт или протокол в
port =— action не сработает так, как ожидается, даже если бан формально зафиксирован в логе.
Что дальше
Fail2ban защищает от атак снаружи, но не менее важно не забывать о рутинном обслуживании сервера изнутри: автоматизируем рутинные задачи обслуживания сервера через cron →