Fail2ban: защита сервисов от перебора паролей
Посмотри на журнал SSH любого сервера, у которого открыт порт 22 в интернет. Через несколько минут после запуска там появятся десятки попыток зайти под root, admin и ubuntu с перебором паролей. Для боевого srv-web01 это не катастрофа, пока пароли сложные или вход по ключам, но шум в логах, нагрузка и риск слабого пароля у какого-нибудь тестового пользователя никуда не деваются. Fail2ban читает логи, находит повторяющиеся неудачные попытки и на время блокирует адрес. В этой статье настроим его на хостах домена itpages.lab.local: для SSH, nginx и с учётом доверенной сети 192.168.10.0/24.
Примеры рассчитаны на Debian 12 и Rocky Linux 9, версия Fail2ban 1.0 и выше. Работай от root.
Принцип работы и установка
Из чего состоит Fail2ban
Три понятия, без которых конфигурация будет непонятной. Фильтр — набор регулярных выражений, которые находят в логе строки о неудачных попытках. Действие — то, что нужно сделать с нарушителем (добавить правило в файрвол, отправить письмо). Jail («тюрьма») — связка фильтра, лога, действия и порогов: сколько ошибок за какое время приводят к бану и на сколько.
# Debian
apt update && apt install -y fail2ban
# Rocky Linux
dnf install -y epel-release
dnf install -y fail2ban fail2ban-firewalld
systemctl enable --now fail2ban
fail2ban-client version
fail2ban-client status
На свежей установке Debian уже включён jail sshd, а на Rocky понадобится включить его явно в конфигурации.
Где править настройки
Главное правило: не редактируй /etc/fail2ban/jail.conf и файлы в filter.d, они перезаписываются при обновлении пакета. Свои настройки пиши в /etc/fail2ban/jail.local или в отдельные файлы /etc/fail2ban/jail.d/*.local. Они переопределяют значения по умолчанию.
Базовая конфигурация
Общие параметры
Создаём файл с настройками по умолчанию для всех jail:
cat > /etc/fail2ban/jail.d/00-defaults.local <<'EOF'
[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 192.168.10.0/24
bantime = 1h
findtime = 10m
maxretry = 5
backend = systemd
banaction = nftables-multiport
banaction_allports = nftables-allports
bantime.increment = true
bantime.factor = 2
bantime.maxtime = 4w
EOF
Что тут сказано. ignoreip — адреса, которые не банятся никогда. Мы внесли всю внутреннюю сеть, иначе один забывчивый администратор, трижды ошибившийся паролем, заблокирует себе доступ. Хотя у такого решения есть цена: если скомпрометирован хост внутри сети, Fail2ban его не остановит. Для особо чувствительных систем сузь исключения до адреса твоей рабочей станции.
Параметры findtime = 10m и maxretry = 5 читаются как «пять ошибок за десять минут — бан». А bantime.increment включает растущий срок: повторный нарушитель получает бан в два раза дольше, потом ещё в два раза, вплоть до четырёх недель. Это отлично работает против ботов, которые возвращаются.
Для backend = systemd Fail2ban читает журнал напрямую через journald, и не нужно указывать пути к логам. На Rocky вместо nftables можно использовать banaction = firewallcmd-multiport (пакет fail2ban-firewalld), если ты пользуешься firewalld.
Jail для SSH
cat > /etc/fail2ban/jail.d/10-sshd.local <<'EOF'
[sshd]
enabled = true
port = ssh
mode = aggressive
maxretry = 4
bantime = 2h
EOF
systemctl restart fail2ban
fail2ban-client status sshd
Режим aggressive объединяет обычный режим с ловлей подбора ключей и преавторизационных сбросов соединения. Он ловит больше, но чуть чаще срабатывает на легитимные сбои, например когда клиент пробует несколько ключей из агента подряд и упирается в лимит MaxAuthTries. Если у тебя такое бывает, оставь mode = normal.
Команда fail2ban-client status sshd покажет текущее число неудач и список забаненных адресов. Для проверки со стороны злоумышленника можно с тестовой машины (не из доверенной подсети) сделать несколько неудачных попыток входа и посмотреть, как адрес оказывается в списке.
Фильтры для других сервисов
Защита nginx на srv-web01
В комплекте есть готовые фильтры для nginx. Подключим два: для HTTP-аутентификации и для ботов, ломящихся по несуществующим путям:
cat > /etc/fail2ban/jail.d/20-nginx.local <<'EOF'
[nginx-http-auth]
enabled = true
port = http,https
logpath = /var/log/nginx/error.log
backend = auto
[nginx-botsearch]
enabled = true
port = http,https
logpath = /var/log/nginx/access.log
maxretry = 10
findtime = 5m
bantime = 12h
backend = auto
EOF
systemctl restart fail2ban
fail2ban-client status
Обрати внимание на backend = auto: для nginx мы читаем файлы, а не журнал, потому что nginx пишет в свои файлы. Если у тебя при этом глобально задан backend = systemd, переопределяй его в jail, иначе фильтр не увидит ни одной строки.
Свой фильтр для собственного приложения
Допустим, внутреннее приложение пишет в /var/log/itpages-app/auth.log строки вида:
2026-10-13 09:41:07 WARN login failed user=admin ip=203.0.113.45
Пишем фильтр. Плейсхолдер <HOST> заменяется Fail2ban на регулярку, ловящую адрес:
cat > /etc/fail2ban/filter.d/itpages-app.conf <<'EOF'
[Definition]
failregex = ^.* WARN login failed user=\S+ ip=<HOST>\s*$
ignoreregex =
EOF
cat > /etc/fail2ban/jail.d/30-itpages-app.local <<'EOF'
[itpages-app]
enabled = true
port = 8080
filter = itpages-app
logpath = /var/log/itpages-app/auth.log
maxretry = 5
backend = auto
EOF
Прежде чем перезапускать сервис, обязательно проверь фильтр на реальном логе. Для этого есть отдельная утилита:
fail2ban-regex /var/log/itpages-app/auth.log /etc/fail2ban/filter.d/itpages-app.conf
fail2ban-regex --print-all-missed /var/log/itpages-app/auth.log /etc/fail2ban/filter.d/itpages-app.conf | head
Вывод покажет, сколько строк совпало и сколько «пропущено». Если совпадений ноль, а ты видишь нужные строки в файле, значит, регулярка не подходит: чаще всего мешают лишние пробелы или другой формат даты.
Управление банами и уведомления
Ручное управление
fail2ban-client status sshd
fail2ban-client set sshd banip 203.0.113.99
fail2ban-client set sshd unbanip 203.0.113.99
fail2ban-client unban --all
fail2ban-client get sshd bantime
nft list ruleset | grep -A3 f2b
Команда unbanip спасёт, если ты или коллега заблокировали сами себя. Последняя строка показывает реальные правила файрвола, которые создал Fail2ban, чтобы убедиться, что бан не только записан в базе, но и действует на сетевом уровне.
Письма о банах
Можно настроить отправку отчётов администратору. Нужно, чтобы на хосте работал локальный почтовый агент (например, msmtp или postfix как релей). Затем добавь в [DEFAULT]:
destemail = admin@itpages.lab.local
sender = fail2ban@srv-web01.itpages.lab.local
mta = sendmail
action = %(action_mw)s
Действие action_mw банит и отправляет письмо с данными whois. Не включай его для публичных серверов с большим потоком ботов: ты получишь сотни писем в день. Для массового случая лучше отправлять сводку раз в сутки командой fail2ban-client status из таймера, либо вести статистику через логи.
Постоянная база и повторные нарушители
Fail2ban хранит баны в SQLite-базе, поэтому после перезапуска сервиса они восстанавливаются. Путь к базе задаётся параметром dbfile в /etc/fail2ban/fail2ban.conf. Для злостных нарушителей есть специальный jail recidive, который читает собственный лог Fail2ban и банит надолго тех, кто уже попадал в бан несколько раз:
cat > /etc/fail2ban/jail.d/90-recidive.local <<'EOF'
[recidive]
enabled = true
logpath = /var/log/fail2ban.log
backend = auto
banaction = %(banaction_allports)s
bantime = 1w
findtime = 1d
maxretry = 3
EOF
systemctl restart fail2ban
Если используешь backend = systemd для fail2ban в Debian 12, где файл /var/log/fail2ban.log может отсутствовать, проверь, что в fail2ban.conf параметр logtarget указывает на файл, а не на SYSLOG или journal.
Fail2ban не заменяет базовую защиту
Fail2ban лечит симптом, но не причину. Параллельно сделай то, что действительно закрывает вектор:
grep -E '^(PasswordAuthentication|PermitRootLogin|MaxAuthTries)' /etc/ssh/sshd_config
sshd -T | grep -E 'passwordauthentication|permitrootlogin|maxauthtries'
Идеальная картина на srv-linux01: PasswordAuthentication no, PermitRootLogin no и вход только по ключам. Тогда перебор паролей бесполезен вообще, а Fail2ban остаётся способом снизить шум и нагрузку. Сам SSH можно ограничить на уровне файрвола доверенной сетью 192.168.10.0/24 и VPN, и тогда внешних попыток не будет вовсе.
Дополнительные приёмы
Белые списки и защита подсетей
Если ты управляешь серверами из конкретных адресов, самый надёжный подход — разрешить SSH только им и оставить Fail2ban как второй рубеж. Параметр ignoreip принимает не только адреса и подсети, но и имена хостов, например admin-ws.itpages.lab.local. Это удобно, если у рабочей станции динамический адрес. Помни, что разрешение имени происходит при старте и перезагрузке конфигурации, поэтому после смены адреса выполни fail2ban-client reload.
Проверка работы действия и файрвола
Бывает, что jail срабатывает, адрес числится в бане, но трафик продолжает идти. Причина обычно в конфликте файрволов: Fail2ban использует nftables, а на хосте работает ufw или firewalld с собственной цепочкой, обрабатывающейся раньше. Проверь порядок цепочек командой nft list chains и убедись, что правила f2b вызываются до разрешающих. На Rocky держись одного инструмента: если используешь firewalld, ставь действие из пакета fail2ban-firewalld и не добавляй вручную правила nftables.
fail2ban-client get sshd banaction
iptables -S | grep f2b | head -3
firewall-cmd --list-rich-rules | head
Нагрузка и производительность
Fail2ban потребляет мало ресурсов, но на сервере с огромными логами фильтр с неудачной регулярной выражением может нагружать процессор. Сравни время обработки с помощью fail2ban-regex, который показывает скорость разбора, и избегай регулярок с начальным «.*» там, где можно привязаться к началу строки. При большом потоке запросов к веб-серверу лучше ограничивать частоту на самом nginx (limit_req) и уже потом подключать Fail2ban для долгих банов: так лишние запросы отсекаются дёшево, ещё до записи в лог.
Наконец, не забудь про IPv6. Если сервис слушает оба стека, а Fail2ban настроен только на IPv4-цепочки, часть нарушителей пройдёт мимо. Современные версии поддерживают IPv6 из коробки, но проверь через fail2ban-client status и тестовую попытку с адреса IPv6, что бан действительно создаётся.
Проверка в боевых условиях
Тест без риска для себя
Прежде чем полагаться на защиту, проверь её с другой стороны. Возьми тестовую машину вне списка ignoreip и вызови срабатывание jail: несколько попыток входа SSH с неверным паролем, например for i in 1 2 3 4 5; do ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no fake@srv-web01.itpages.lab.local true; done. После пятой попытки соединение должно зависнуть или быть отклонено, а адрес появиться в fail2ban-client status sshd. Затем сними бан командой unbanip и убедись, что доступ вернулся.
Мониторинг самого Fail2ban
Служба, которая молча остановилась, хуже, чем её отсутствие: ты думаешь, что защищён. Добавь проверки systemctl is-active fail2ban и количество активных jail в мониторинг. Заодно собирай статистику банов: число уникальных адресов за сутки, страны источников и самые популярные имена пользователей в попытках. Скачок в несколько раз сигнализирует о целевой атаке и повод проверить, нет ли утечки паролей. Простой отчёт делается из лога: grep 'Ban ' /var/log/fail2ban.log | awk '{print $NF}' | sort | uniq -c | sort -rn | head.
Полезно держать запасную дверь: например, второй SSH-порт, доступный только из VPN или внутренней сети 192.168.10.0/24, с отдельным jail или вовсе без него. Так ты не запрёшь себя при ошибке настройки, а ошибки при первом знакомстве с инструментом неизбежны.
Частые ошибки и как их избежать
- Правка jail.conf вместо jail.local. После обновления пакета настройки пропадут, а ты узнаешь об этом, когда сервис вдруг перестанет банить. Всё своё держи в
jail.d/*.localи проверяй итог командойfail2ban-client -d | head -50. - Неправильный backend и путь к логу. Jail включён, но счётчик «Total failed» всегда ноль: фильтр ничего не читает. Проверь
fail2ban-regexна реальном файле или журнале и посмотриjournalctl -u fail2banна предупреждения. - Бан самого себя. Без
ignoreipты можешь отрезать себе доступ к srv-web01, особенно при тестах. Заранее добавь свою подсеть и держи запасной путь: консоль гипервизора или другой хост, откуда можно выполнитьunbanip.
Что дальше
Администрирование Linux — это набор связанных навыков, вот соседние темы серии: