Короткий ответ
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-sshdNo 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-legacy | backend firewall |
Отличие от «боты есть, но это норма»: если 22 открыт паролем, даже идеальный jail — заплатка. Отличие от настройки с нуля: здесь чините уже установленный и «вроде включённый» Fail2Ban.
Возможные причины
- В Debian/Ubuntu
jail.d/defaults-debian.confвключаетsshd, а вашjail.localвыставилenabled = falseили переименовал jail. backend = autoсмотрит/var/log/auth.log, на хосте только journald.failregexне совпадает сjournalctl -u ssh(другой tag,sshd[nid]:vsssh).banaction = iptables-multiportпри чистом nft без compat, или наоборот UFW пересобирает набор и сносит цепочки f2b.ignoreipсодержит0.0.0.0/0или весь интернет «чтобы себе не баниться».maxretryогромный,findtimeкороткий — порог не достигается.- Фильтр
mode = aggressivevsnormal: не ловит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.conf0 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».
Как проверить, что проблема устранена
fail2ban-client status sshdпоказываетCurrently failedпри живых попытках.- После порога —
Total bannedрастёт, IP есть вBanned IP list. - С бана:
nc -vz 10.0.20.10 22с этого IP — timeout/reject, неFailed password. - С
ignoreiphop10.0.20.0/24— вы не забанены. 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 потому что «есть облако».