fail2ban на Ubuntu: защита SSH от перебора пароля
fail2ban читает /var/log/auth.log, ловит N неудачных попыток входа с одного IP за окно времени и временно банит этот IP через UFW или nftables. После UFW это второй слой защиты SSH: фаервол режет порты, fail2ban — назойливых ботов, которые подобрались к разрешённому 22/tcp. В статье — установка fail2ban на Ubuntu 24.04, дисциплина jail.local вместо jail.conf, готовый jail для sshd, диагностика fail2ban-client status и что делать, если забанили самого себя.
fail2ban на Ubuntu: защита SSH от перебора пароля
fail2ban читает /var/log/auth.log, ловит N неудачных попыток входа с одного IP за окно времени и временно банит этот IP через UFW или nftables. После UFW это второй слой защиты SSH: фаервол режет порты, fail2ban — назойливых ботов, которые подобрались к разрешённому 22/tcp. В статье — установка fail2ban на Ubuntu 24.04, дисциплина jail.local вместо jail.conf, готовый jail для sshd, диагностика fail2ban-client status и что делать, если забанили самого себя.
Зачем fail2ban, если уже есть UFW
UFW и fail2ban решают разные задачи. UFW — статический фильтр на уровне порта: «кто угодно с любого IP может стучаться в 22/tcp». fail2ban — динамический: «если конкретный IP уронил пароль 5 раз за 10 минут, заблокируй его на час».
Чем это лучше ufw limit ssh:
ufw limitрежет всех, кто превысил порог соединений, — не различает успешные и неудачные попытки. fail2ban смотрит именно на записьFailed passwordилиInvalid userв логах.ufw limitзабывает поведение быстро (30 сек). fail2ban помнит часами и сутками —bantimeнастраивается.- fail2ban работает не только для SSH: тот же подход применим к
nginx-botsearch,postfix-sasl,recidiveи десяткам других готовых jail-ов.
Связка «UFW + fail2ban + SSH-ключи без пароля» — стандартный стек для серверного Ubuntu. fail2ban не заменяет ключи: он защищает от шумового брутфорса, чтобы логи и journalctl не тонули в Failed password from 198.51.100.X.
Установка fail2ban на Ubuntu
В репозиториях Ubuntu 24.04 LTS лежит fail2ban 1.0.x — это нормальный релиз, ничего из ppa или pip ставить не нужно:
sudo apt update
sudo apt install fail2ban
После установки демон уже запущен и enabled через systemd, но дефолтных jail-ов не активных: с заводскими настройками fail2ban читает jail.conf, в котором все jail помечены enabled = false. Включаем минимум осознанно — через jail.local.
Проверим, что демон жив:
sudo systemctl status fail2ban
sudo fail2ban-client ping
# должен ответить: Server replied: pong
Базовая настройка: jail.local вместо jail.conf
Главное правило fail2ban — не редактировать /etc/fail2ban/jail.conf. Это файл из пакета, при apt upgrade он перезаписывается, и ваши правки потеряются. Все локальные изменения кладутся в jail.local или в отдельные файлы /etc/fail2ban/jail.d/*.local.
Минимальный /etc/fail2ban/jail.local:
[DEFAULT]
# IP, которые никогда не банятся (LAN, ваш bastion-хост, мониторинг)
ignoreip = 127.0.0.1/8 ::1 192.168.0.0/16
# Окно наблюдения и порог
findtime = 10m
maxretry = 5
# Длительность бана
bantime = 1h
# Бан-механизм. На 24.04 UFW под капотом nftables — fail2ban знает оба.
banaction = ufw
# Куда писать события (помимо /var/log/fail2ban.log)
backend = systemd
[sshd]
enabled = true
port = ssh
# Если SSH перенесён на 2222 — раскомментируйте и закомментируйте строку выше
# port = 2222
Что значит каждая строка:
findtime+maxretry— «5 фейлов за 10 минут → бан». На свежем сервере без ключей это может оказаться слишком жёстко (вы сами успеете 5 раз промахнуться); поднимите до 10. Когда настроена авторизация по ключу — 5 нормально.bantime— час разумный дефолт. Для адресов, которые попадаются повторно, есть отдельный jailrecidive, но это уже надстройка.banaction = ufw— fail2ban будет добавлять правила в UFW (ufw insert 1 deny from <ip>) вместо прямой работы с iptables/nftables. Так бан виден вsudo ufw status numberedи не конфликтует с вашими правилами фаервола.backend = systemd— на 24.04 sshd пишет в systemd journal черезjournalctl, а не в plain-файл. Сbackend = systemdfail2ban читает journal напрямую — это надёжнее, чем парсить/var/log/auth.log(на минимальных образах его может не быть).[sshd]— встроенный jail из пакета. Включается одной строчкойenabled = true.
После правки — рестарт:
sudo systemctl restart fail2ban
sudo fail2ban-client status
# должен показать: Jail list: sshd
Правила fail2ban: filter, action, jail
Внутри fail2ban три понятия:
- filter — регулярка, которая ловит «плохое» событие в логе. Лежат в
/etc/fail2ban/filter.d/*.conf. Для SSH —sshd.conf, ловитFailed password,Invalid user,Connection closed by authenticating user. - action — что делать, когда фильтр сработал N раз.
/etc/fail2ban/action.d/*.conf. Для UFW —ufw.conf(actionban = ufw insert 1 deny from <ip>). Возможны и другие: отправить письмо, дёрнуть webhook, вызвать sshd-route-tarpit. - jail — связка фильтра, action и параметров (
maxretry,bantime,port,logpath). Описывается в[имя]-секцияхjail.conf/jail.local/jail.d/*.local.
Чтобы посмотреть, какие правила fail2ban доступны из коробки:
ls /etc/fail2ban/filter.d/ # фильтры
ls /etc/fail2ban/action.d/ # actions
sudo fail2ban-client get sshd logpath
Свои фильтры пишутся редко — для типовых сервисов (sshd, nginx, postfix, dovecot, vsftpd, recidive) уже всё готово. Своя дисциплина обычно сводится к включению нужных jail в jail.d/*.local и подкрутке maxretry/bantime.
Проверка: fail2ban-client status
Главная команда диагностики — fail2ban-client status. Без аргументов она показывает все активные jail, с именем jail — детали по конкретному:
sudo fail2ban-client status
# Status
# |- Number of jail: 1
# `- Jail list: sshd
sudo fail2ban-client status sshd
# Status for the jail: sshd
# |- Filter
# | |- Currently failed: 3
# | |- Total failed: 127
# | `- File list: /var/log/auth.log
# `- Actions
# |- Currently banned: 2
# |- Total banned: 38
# `- Banned IP list: 45.227.X.Y 185.220.X.Z
Total banned — сколько IP побывали в бане за всё время работы. На свежем сервере с открытым 22/tcp эта цифра растёт сама. Currently banned — кто сидит в бане прямо сейчас.
Полезные команды-однострочники:
# IP, которые сейчас под баном в sshd-jail
sudo fail2ban-client get sshd banip
# Снять бан с конкретного IP
sudo fail2ban-client unban 198.51.100.42
# Снять все баны
sudo fail2ban-client unban --all
# Перечитать конфиги без рестарта демона
sudo fail2ban-client reload
Когда забанили самого себя
Промахнулись паролем 5 раз в SSH с офиса — теперь не пускает. Варианты:
- Через консоль провайдера / VNC. Заходим напрямую и снимаем бан:
sudo fail2ban-client unban <ваш_внешний_ip>. Внешний IP можно посмотреть на любом ifconfig.me. - С другого IP. Если есть второй сервер, мобильный интернет, VPS — заходим оттуда, снимаем бан с офисного IP.
- Профилактика. Внести свой постоянный IP в
ignoreipв[DEFAULT]секцииjail.local. Послеreloadfail2ban не будет отслеживать его вообще:
[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 203.0.113.10
Не забывайте: ignoreip — это «полное игнорирование», ваши собственные опечатки тоже не будут считаться. Это нормально для выделенных IP; для динамических лучше использовать ignorecommand или просто включить ключевую авторизацию и убрать пароль.
Тестирование фильтра без боевых банов
Перед заливкой кастомного фильтра в прод полезно прогнать его на реальных логах через fail2ban-regex — он покажет, какие строки matched и сколько было бы банов, не трогая реальный jail:
sudo fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf
# или с journald (24.04+):
sudo fail2ban-regex \
systemd-journal \
/etc/fail2ban/filter.d/sshd.conf
Вывод: количество matched / not-matched, примеры строк, регулярки. Если matched = 0 — фильтр не ловит ваш формат логов; типовая причина на 24.04 — пытаетесь читать /var/log/auth.log, которого нет (logging-механизм через journal, файл не создаётся). Решение — backend = systemd в jail.local, как в примере выше.
Логи самого fail2ban
Демон пишет всё, что банит и разбанивает, в /var/log/fail2ban.log. Полезно во время отладки:
sudo tail -f /var/log/fail2ban.log
# Все баны за сегодня
sudo grep "$(date +%Y-%m-%d).*Ban" /var/log/fail2ban.log | wc -l
Если по какой-то причине /var/log/fail2ban.log пустой — смотрите journalctl: sudo journalctl -u fail2ban -n 200.
Частые вопросы
Какой backend ставить на Ubuntu 24.04 — auto или systemd?
systemd. На 24.04 sshd пишет в journald, а файл /var/log/auth.log создаётся только если установлен rsyslog. С backend = auto fail2ban в half-cases пытается читать несуществующий файл и тихо ничего не банит. backend = systemd забирает события напрямую из journal — надёжнее.
Что если SSH у меня на нестандартном порту?
В секции [sshd] поменяйте port = ssh на port = 2222 (или ваш номер). Фильтр — тот же, sshd пишет в журнал одинаково независимо от порта. Если параллельно правите Port в /etc/ssh/sshd_config — не забудьте sudo ufw allow 2222/tcp до рестарта sshd.
fail2ban или ufw limit ssh — что выбрать?
Дополняют, а не заменяют. ufw limit работает на уровне TCP-соединений и режет любые всплески (включая ваши собственные rsync-сессии). fail2ban работает по факту неудачной аутентификации — точнее, но требует, чтобы попытка дошла до sshd и попала в журнал. На проде ставьте оба: ufw limit рубит флуд соединений, fail2ban — реальный брутфорс пароля.
Можно ли защитить fail2ban-ом nginx или postgres?
Да. В /etc/fail2ban/filter.d/ уже есть фильтры nginx-http-auth, nginx-botsearch, postfix-sasl и другие. Включаются они теми же блоками [nginx-botsearch]\nenabled = true в jail.local. Для своих сервисов пишется кастомный фильтр — регулярка по строкам лога. Но это уже отдельная тема.
Куда смотреть логи самого fail2ban?
Файл /var/log/fail2ban.log (старая schoo) или journalctl -u fail2ban (рекомендуемый способ на 24.04). Там видны строки [sshd] Ban 198.51.100.X и [sshd] Unban 198.51.100.X — каждое действие фиксируется.
Что запомнить
- Не править
/etc/fail2ban/jail.conf— все изменения только вjail.localили/etc/fail2ban/jail.d/*.local. - На 24.04 ставить
backend = systemdв[DEFAULT]— иначе fail2ban будет читать несуществующийauth.log. banaction = ufw— баны видны вufw statusи не конфликтуют с вашими правилами фаервола.- Свой постоянный IP — в
ignoreip, чтобы не забанить себя случайно во время отладки. fail2ban-client status sshd— проверка после каждой правки.Total bannedрастёт сам, это нормально.- Перед прод-заливкой кастомного фильтра — прогнать через
fail2ban-regexна реальных логах.