Fail2ban на Ubuntu 24: настройка против brute force
Fail2ban — простой и надёжный инструмент против перебора паролей. Я ставлю его на каждый VPS первым же шагом после базовой настройки. На Ubuntu 24.04 он работает без сюрпризов, но есть нюансы конфигурации, которые знают не все. Расскажу, что у меня настроено по умолчанию.
Что делает Fail2ban
Идея простая: парсит логи сервисов (по regex), считает количество неудачных попыток с одного IP за окно времени, и если их слишком много — блокирует IP в файрволе на заданное время. Вернее всего работает на SSH, на nginx-ручках логина, на любых endpoint-ах, которые пишут в лог факт неуспешного входа.
Установка
sudo apt update
sudo apt install -y fail2ban
sudo systemctl status fail2banНа Ubuntu 24.04 ставится свежая версия (1.0.x), которая умеет работать с nftables и systemd-journal без лишних плясок.
Базовая конфигурация
Никогда не редактируй /etc/fail2ban/jail.conf напрямую. Он перезаписывается при обновлениях. Все свои настройки кладём в /etc/fail2ban/jail.local.
sudo tee /etc/fail2ban/jail.local >/dev/null <<'EOF'
[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5
backend = systemd
banaction = iptables-multiport
# белый список — твоя сеть, чтобы случайно не забанить себя
ignoreip = 127.0.0.1/8 ::1 10.0.0.0/8 192.168.0.0/16
[sshd]
enabled = true
port = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s
[nginx-http-auth]
enabled = true
port = http,https
logpath = /var/log/nginx/error.log
[nginx-limit-req]
enabled = true
port = http,https
logpath = /var/log/nginx/error.log
findtime = 10m
maxretry = 10
EOF
sudo systemctl reload fail2banЧто важно:
- bantime = 1h: первый бан на час. На повторных нарушениях у меня recidive jail продлевает.
- findtime = 10m, maxretry = 5: 5 неудач за 10 минут — бан.
- backend = systemd: на Ubuntu 24 SSH пишет логи в journald, не в файл. Этот бэкенд читает journald напрямую.
- ignoreip: добавь сюда свой статический IP, если он есть. Иначе случайная серия неудачных входов и сам себя залочишь.
Recidive jail — повторные нарушители
Полезный приём: банить надолго тех, кто уже банился несколько раз.
sudo tee -a /etc/fail2ban/jail.local >/dev/null <<'EOF'
[recidive]
enabled = true
logpath = /var/log/fail2ban.log
bantime = 1w
findtime = 1d
maxretry = 3
EOF
sudo systemctl reload fail2banЛогика: если IP попадал в любой бан 3 раза за день — кладём его в recidive jail на неделю. На моих серверах это срезает заметную долю атакующего трафика.
Защита nginx
Базовый nginx-jail из коробки ловит ошибки авторизации в стандартном формате. Если у тебя своё API с ручкой /api/auth/sign-in, имеет смысл добавить свой filter и jail.
Filter /etc/fail2ban/filter.d/myapp-auth.conf:
[Definition]
failregex = ^<HOST> .* "POST /api/auth/sign-in.* HTTP/.*" 401 .*$
^<HOST> .* "POST /api/auth/sign-in.* HTTP/.*" 429 .*$
ignoreregex =Jail в jail.local:
[myapp-auth]
enabled = true
port = http,https
filter = myapp-auth
logpath = /var/log/nginx/myapp_access.log
findtime = 10m
maxretry = 8
bantime = 30mПроверяем regex:
sudo fail2ban-regex /var/log/nginx/myapp_access.log /etc/fail2ban/filter.d/myapp-auth.confДолжно показать «matched ... lines», если в логе уже есть атаки. Если 0 совпадений — формат лога не такой, regex надо подправить.
Защита от ddos через limit_req
В nginx стоит limit_req_zone на чувствительные ручки. Каждый отказ пишется в error.log как limiting requests. Стандартный jail nginx-limit-req это ловит и банит на уровне файрвола.
Если правил limit_req много, легко наловить кучу банов. Контролируй maxretry и findtime: 10 нарушений за 10 минут с одного IP — нормальный потолок.
Проверка состояния
sudo fail2ban-client status
sudo fail2ban-client status sshdПервая команда покажет список активных jail, вторая — детали по конкретному. В выводе видно, сколько IP сейчас забанено и список адресов.
Разбанить вручную:
sudo fail2ban-client set sshd unbanip 1.2.3.4Или весь jail:
sudo fail2ban-client unban --allУведомления
По умолчанию fail2ban пишет в журнал, но не уведомляет тебя. Можно навесить email через action:
[DEFAULT]
destemail = admin@example.ru
sender = fail2ban@example.ru
mta = sendmail
action = %(action_mwl)saction_mwl — стандартный action, который пишет email с whois и log-tail для забаненного IP. Удобно понимать, кто, откуда, и что именно делал.
Для уведомлений в Telegram я использую отдельный action-скрипт, который вызывает curl на бот. Не самое элегантное решение, но работает.
Подводные камни
Ipv6
Старые версии fail2ban плохо работали с IPv6. На Ubuntu 24 уже всё ок, но если в твоей конфигурации banaction = iptables-..., IPv6 может игнорироваться. Включай nftables:
[DEFAULT]
banaction = nftables-multiport
banaction_allports = nftables-allportsnftables работает и с v4, и с v6 одинаково.
Конфликт с ufw
fail2ban и ufw оба работают с iptables. Конфликта нет, но полезно понимать, какой инструмент за что отвечает: ufw держит «разрешено / запрещено», fail2ban добавляет ban-правила выше. Я никогда не отключаю ufw из-за fail2ban.
Неправильный formatter
Если nginx у тебя пишет в JSON или кастомный формат, стандартные filter-ы не сработают. Либо пиши свой filter под свой формат, либо переключи nginx на стандартный combined.
В рут-логе systemd
На Ubuntu 24 SSH лога /var/log/auth.log может не быть, всё едет в journald. Если у тебя backend = auto или file — fail2ban не найдёт лог. Используй backend = systemd.
За nginx в облаке
Если приложение за nginx, а тот за CloudFlare — в логе будет IP CloudFlare, а не пользователя. Файл log_format нужно настроить так, чтобы первым логировался $http_x_forwarded_for, и filter должен его ловить.
Whitelist своего CI
Если у тебя CI/CD дёргает API сервера и иногда промахивается с авторизацией, можно случайно забанить IP CI. Чтобы не страдать, добавляй адреса runner-ов в ignoreip:
ignoreip = 127.0.0.1/8 ::1 10.0.0.0/8 192.168.0.0/16 1.2.3.4/32Где 1.2.3.4 — IP твоего CI или office-сети.
Что у меня всегда стоит на новом VPS
- SSH с ключами, парольный вход выключен.
- fail2ban с jails: sshd, nginx-http-auth, nginx-limit-req, recidive.
- Свой jail на /api/auth/sign-in, если приложение есть.
- action_mwl + email или Telegram-уведомления.
- backend = systemd, banaction = nftables-multiport.
Это занимает 15 минут и закрывает 90% нагрузки от автоматических сканеров. Полностью защититься от ddos одним fail2ban не получится, но от тривиальных сканеров — отлично. Дальше уже идут полноценные WAF и CDN, но это совсем другая история.