Короткий ответ

Fail2Ban банит только если: jail enabled, фильтр матчит реальные строки журнала, backend читает тот же источник (часто systemd, не мёртвый auth.log), banaction пишет в тот firewall, который реально фильтрует пакеты (nftables или UFW, не «iptables в пустоту»). Диагностика: fail2ban-client status sshd, fail2ban-regex, nft list ruleset / ufw status. Не чините «не банит» командой ufw disable или systemctl stop ssh. Если пароль SSH ещё включён — сначала ключи, Fail2Ban не замена.

Хост host.example (10.0.20.10), пользователь admin.

Симптомы и как отличить

  • В fail2ban.log есть Filter ready, нет Ban;
  • Currently banned: 0 при тысячах Failed password в journal;
  • iptables -L f2b-sshd No chain, при этом nft живой;
  • jail называется sshd, а unit — ssh.service (Ubuntu).
НаблюдениеСлой
Jail disabled в jail.dконфиг
regex 0 matchedфильтр vs формат лога
Ban есть, пакеты проходятне тот table/hook, облако SG
Ban есть только IPv4нет banaction_allports / ip6
UFW active, f2b пишет iptables-legacybackend firewall

Отличие от «боты есть, но это норма»: если 22 открыт паролем, даже идеальный jail — заплатка. Отличие от настройки с нуля: здесь чините уже установленный и «вроде включённый» Fail2Ban.

Возможные причины

  1. В Debian/Ubuntu jail.d/defaults-debian.conf включает sshd, а ваш jail.local выставил enabled = false или переименовал jail.
  2. backend = auto смотрит /var/log/auth.log, на хосте только journald.
  3. failregex не совпадает с journalctl -u ssh (другой tag, sshd[nid]: vs ssh).
  4. banaction = iptables-multiport при чистом nft без compat, или наоборот UFW пересобирает набор и сносит цепочки f2b.
  5. ignoreip содержит 0.0.0.0/0 или весь интернет «чтобы себе не баниться».
  6. maxretry огромный, findtime короткий — порог не достигается.
  7. Фильтр mode = aggressive vs normal: не ловит Invalid user или наоборот.

Диагностика

1. Демон и список jail

systemctl status fail2ban --no-pager -l
sudo fail2ban-client ping
sudo fail2ban-client status
sudo fail2ban-client status sshd

Нет jail sshd — смотрите sshd, не ssh. Имена jail ≠ имя systemd unit.

sudo grep -RniE '^\[sshd\]|enabled|backend|banaction|logpath|journalmatch' \
  /etc/fail2ban/jail.conf /etc/fail2ban/jail.local /etc/fail2ban/jail.d/

2. Откуда читают логи

ls -l /var/log/auth.log /var/log/syslog 2>/dev/null
sudo journalctl -u ssh -n 20 --no-pager

Прогон фильтра по живым данным:

sudo journalctl -u ssh -n 200 --no-pager > /tmp/ssh-journal.txt
sudo fail2ban-regex /tmp/ssh-journal.txt /etc/fail2ban/filter.d/sshd.conf

0 matched при видимых Failed password — не тот фильтр/datepattern, или в файле нет префикса, который ждет fail2ban для systemd.

Для systemd backend в jail должно быть примерно:

[sshd]
enabled = true
backend = systemd
journalmatch = _SYSTEMD_UNIT=ssh.service + _COMM=sshd

Точный journalmatch сверьте с man jail.conf вашей версии пакета и с systemctl show ssh -p Id,FragmentPath. Не копируйте sshd.service с RHEL на Ubuntu.

3. Куда пишется бан

sudo fail2ban-client get sshd banip
sudo fail2ban-client get sshd actions
sudo nft list ruleset | grep -i -A2 fail2ban
sudo iptables -L -n 2>/dev/null | grep -i f2b
sudo ufw status numbered

Если Ban в логе fail2ban есть, а nft/ufw пустой — action не применяется (python-ошибка action, нет прав NET_ADMIN — редко, чаще неверный banaction).

sudo tail -n 80 /var/log/fail2ban.log
sudo journalctl -u fail2ban -n 80 --no-pager

Решение

Сценарий A. Jail выключен или читает не тот лог

Создайте только override, не копируйте весь jail.conf:

sudo tee /etc/fail2ban/jail.d/sshd-ubuntu.local >/dev/null <<'EOF'
[sshd]
enabled = true
backend = systemd
port = ssh
filter = sshd
maxretry = 4
findtime = 10m
bantime = 1h
ignoreip = 127.0.0.1/8 ::1 10.0.20.0/24
EOF
sudo fail2ban-client reload
sudo fail2ban-client status sshd

Подставьте свой admin-CIDR в ignoreip, не 0.0.0.0/0.

Сценарий B. Regex не матчит

Сначала добейтесь ненулевого fail2ban-regex. Режим фильтра:

[sshd]
filter = sshd[mode=aggressive]

Aggressive ловит больше Invalid user/Failed publickey. Проверьте, что не баните себя с jump-хоста — ignoreip.

Не пишите самодельный failregex «с форума» без якорей: легко словить ложные баны по строке Failed в другом сервисе.

Сценарий C. Бан не попадает в firewall

Если включён UFW — action должен дружить с ним:

[sshd]
banaction = ufw

Если UFW нет, политика — nftables:

[DEFAULT]
banaction = nftables-multiport
banaction_allports = nftables-allports

Перезагрузка:

sudo fail2ban-client reload
# тестовый бан своего лабораторного IP, не прод-шлюза
sudo fail2ban-client set sshd banip 203.0.113.10
sudo nft list ruleset | grep 203.0.113.10
sudo fail2ban-client set sshd unbanip 203.0.113.10

Пакет fail2ban на Ubuntu 22.04/24.04 содержит action nftables-*.conf и ufw.conf. Не выдумывайте banaction = firewalld.

Параллельно два менеджера набора (ручной nftables.service + UFW + f2b iptables) — типичный «бан в логе, трафик жив». Оставьте один datapath: UFW или свой /etc/nftables.conf, Fail2Ban — action под него. См. firewall не настроен.

Сценарий D. Банит, но атака идёт на другой порт/сервис

Jail sshd не закрывает 443 и 3306. Лишние слушатели — лишние порты. Web brute-force — отдельный jail, не «подкрутить sshd maxretry».

Как проверить, что проблема устранена

  1. fail2ban-client status sshd показывает Currently failed при живых попытках.
  2. После порога — Total banned растёт, IP есть в Banned IP list.
  3. С бана: nc -vz 10.0.20.10 22 с этого IP — timeout/reject, не Failed password.
  4. С ignoreip hop 10.0.20.0/24 — вы не забанены.
  5. ufw status / nft list по-прежнему active, default incoming не accept.

Сохраните status sshd и кусок ruleset в заявку.

Если не помогло

  • Have not found any log: backend systemd без journalmatch или unit не ssh.service.
  • После ufw reload баны слетают: переходите на banaction = ufw или встраивайте f2b в nft атомарно.
  • Облако: NSG пропускает до DNAT, гостевой бан бесполезен для пакетов, которые не доходят — режьте SG.
  • IPv6 боты: включите IPv6 в fail2ban (allowipv6 = auto в свежих версиях) и ufw.
  • SELinux на Ubuntu не штатный путь; не ставьте SELINUX=disabled. На RHEL смотрите AVC на fail2ban-server, не отключайте enforcing навсегда.
  • Демон падает на python traceback в action — читайте traceback, не Restart=always как решение.

Профилактика

  • Jail в jail.d/*.local в git/ansible, не ручной jail.conf.
  • Мониторинг: Currently banned, рост fail2ban.log ошибок action.
  • После смены firewall (UFW ↔ nft) — тест banip в том же чеклисте.
  • Слой 0: ключи и CIDR, см. sshd.

FAQ

Почему status sshd: No such jail?

Имя не совпало или jail disabled. fail2ban-client status без аргумента — список. Не путайте с systemctl status ssh.

Можно ли bantime = -1?

Постоянный бан живёт в fail2ban, пока не unban/reload. Для WAN-сканеров лучше конечный bantime + firewall CIDR. Вечный бан тысяч IP раздует набор.

fail2ban-regex по auth.log 0, journal полный

На 24.04 часто нет rsyslog. Ставьте backend = systemd, не создавайте пустой auth.log «для галочки».

Ban есть, SSH с того IP всё равно входит

Пакет не проходит через chain f2b: другой NIC, IPv6, порт не ssh в jail, или подключение уже established. Проверьте ss -tp | grep 22.

Стоит ли банить на уровне провайдера?

Да, SG/WAF для объёма. Fail2Ban — хостовый слой. Не отключайте хостовый firewall потому что «есть облако».