Будь-який сервер із відкритим SSH за кілька годин в інтернеті починає ловити фоновий брутфорс: боти перебирають root, admin, 123456 цілодобово. Руками банити їх безнадійно. fail2ban робить це сам: читає логи, рахує невдалі входи з кожного IP і, коли той переходить межу, тимчасово блокує його на рівні файрвола. Атакуюча сторона просто дропається.
Ідея стара й проста, але на свіжому Debian 13 «trixie» є кілька нюансів, через які у новачків fail2ban мовчки не банить. Розберемо все на живому прикладі - і з розбором цих граблів у кінці.
Що потрібно зробити?#
Поставити fail2ban на свіжий Debian 13, увімкнути охорону SSH і - найцікавіше - самому зіграти брутфорсера з сусідньої машини, щоб побачити бан у дії: як після кількох невдалих спроб IP вилітає, а наступні підключення одразу відбиваються.
З чим працюю?#
Дві одноразові машини в ізольованій пісочниці, обидві Debian 13:
srv-01.linuxway.com.ua(10.10.60.102) - сервер, який захищаємо;attacker(10.10.60.103) - з нього ломитимемось.
Так бан буде по-справжньому: fail2ban банитиме реальний чужий IP, а не loopback.
Ставимо fail2ban#
Встановлення - один рядок. Одразу додаю nftables явно (чому - побачимо в кінці, це головна заковика trixie):
| |
На Debian пакет приходить уже з розумними дефолтами: сервіс запущений, а jail для SSH увімкнений із коробки. Перевіримо:
| |
Залишається тільки підкрутити поведінку під себе. Правила живуть у /etc/fail2ban/jail.conf, але редагувати його не треба - він перезаписується при оновленні. Замість цього кладемо перевизначення в /etc/fail2ban/jail.local (він читається останнім і переживає apt upgrade):
| |
Три промахи за 10 хвилин - бан на 10 хвилин. ignoreip - це білий список, щоб не заблокувати самого себе (додай сюди свою робочу адресу, якщо ходиш зі статичного IP). Застосовуємо:
| |
Усе, пастка на брутфорс зведена. Тепер зіграймо того, від кого захищаємось.
Хтось стукає - і одразу в бан#
З машини attacker запускаю примітивний перебір паролів до srv-01 - кілька спроб поспіль зі свідомо неправильними паролями:
| |
Ліворуч - живий статус fail2ban на сервері, праворуч - те, що бачить брутфорсер. Дивись на лічильник Currently failed: він росте 1, 2, 3 - і на третій спробі IP вилітає в бан, а наступні підключення отримують Connection refused:
Найкраще тут - момент перемикання. Щойно Currently banned стає 1 і в Banned IP list з’являється 10.10.60.103, атакувальник немовби впирається в стіну: сервер більше навіть не питає пароль, а просто відбиває кожне з’єднання. І так - автоматично, без жодного твого втручання.
А що саме сталося?#
fail2ban не чіпає конфіг sshd і не рве активні сесії - він лише додає кривдника у nftables-сет, а окреме правило відкидає все з нього. Подивитись «начинку» бану можна прямо в nftables:
| |
| |
А якщо зібрати події з логів (/var/log/fail2ban.log для рішень fail2ban і systemd journal для самих спроб), складається наочна картина атаки: три невдалі входи - і бан.

Коли сервер постоїть відкритим в інтернеті добу, у цій таблиці будуть вже не один IP, а сотні - з усього світу. І всі вони будуть забанені, поки ти спав.
Debian 13: три заковики, на яких спотикаються#
Саме на trixie fail2ban поводиться трохи інакше, ніж у старих гайдах. Три речі варто знати, бо через них здається, що «воно не працює»:
Немає
/var/log/auth.log. На сучасному Debian немаєrsyslogіз коробки, і sshd пише лише в systemd journal. Старий рецептbackend = autoтут нічого не побачить - потрібенbackend = systemd. На щастя, для sshd-jail Debian уже виставив його за замовчуванням, тому все працює одразу. Але якщо раптом перепишеш backend на файловий - jail осліпне.Бан іде через nftables, а не iptables. Debian 13 на nftables, і fail2ban тут за замовчуванням використовує
nftables. Проблема в іншому: пакет лише рекомендуєnftables | iptables. Якщо на машині вже стоїтьiptables, apt вважає умову виконаною й не ставитьnftables- тоді бан мовчки не накладається (jail активний, спроби рахуються, а блокування немає). Тому й ставимоfail2ban nftablesразом, або перевіряємоwhich nftпісля встановлення.sshd-jail уже увімкнений. На Debian його не треба вмикати - він
enabledіз коробки. Новачки через це двічі описують[sshd]у різних місцях і отримують конфлікт конфігурації. Уjail.localдостатньо лише підкрутити параметри, а не включати заново.
Куди далі#
fail2ban - класика, яка чудово робить одну річ: ловить брутфорс по логах на одному хості. Але він бачить лише те, що вже сталося у тебе, і банить по простих правилах. Є сучасніший підхід - CrowdSec: він теж банить, але ще й аналізує поведінку, ділиться репутацією IP зі спільнотою (тебе банять ще до того, як бот дістанеться саме до тебе) і має веб-консоль із метриками.
Його й візьмемо наступним - поставимо поруч, нацькуємо той самий брутфорс і подивимось, чим CrowdSec відрізняється від fail2ban на практиці.



