Коротко. fail2ban читает логи сервисов, считает неудачные попытки входа с одного IP и на время добавляет этот адрес в правила firewall. Ставится через apt, настраивается в файле jail.local, а не в jail.conf. Ключевые параметры — maxretry, findtime, bantime и ignoreip. На современных Ubuntu логи sshd лежат в journald, поэтому джейлу нужен backend systemd, иначе он молча не сработает.
Что fail2ban делает и чего не делает
fail2ban — это демон, который следит за текстовыми логами (или журналом systemd), ищет в них строки, подходящие под регулярное выражение фильтра, и, если с одного IP-адреса за окно findtime набралось maxretry совпадений, вызывает действие: обычно добавление правила DROP или REJECT в firewall на время bantime. По истечении bantime правило снимается. Всё. Больше fail2ban ничего не делает.
Из этого следуют неприятные, но важные ограничения, которые стоит понимать до внедрения.
- Это не firewall. fail2ban не закрывает порты и не задаёт политику доступа. Он лишь добавляет временные правила в уже существующий firewall (iptables, nftables, ufw, firewalld). Если у вас порт СУБД торчит наружу, fail2ban не поможет — нужен базовый фильтр пакетов и разбор открытых портов.
- Это не защита от распределённого брутфорса. Современный ботнет делает 2–3 попытки с каждого из десятков тысяч адресов. Порог maxretry никогда не срабатывает, а если и срабатывает, вы забаните один адрес из пула. Против такого сценария работает не fail2ban, а отключение парольной аутентификации и лимиты на уровне приложения.
- Это не WAF. fail2ban не разбирает тело запроса, не понимает SQL-инъекции и не проверяет payload. Он видит только то, что сервис сам записал в лог.
- Это реактивная мера. Первые maxretry попыток всегда проходят. Если пароль подобрался с третьей попытки при maxretry = 5, бан бесполезен.
- Он бессилен без логов. Если сервис не пишет неудачные входы или пишет их в формате, который не ловит фильтр, джейл будет висеть с нулевым счётчиком и создавать ложное ощущение защиты.
fail2ban — это способ убрать фоновый шум и снизить нагрузку на sshd, а не заменить нормальную аутентификацию. Ключи вместо паролей,
PasswordAuthentication noи закрытые наружу служебные порты дают на порядок больше, чем любая настройка джейлов.

Установка fail2ban на Ubuntu и Debian
Пакет есть в основных репозиториях обоих дистрибутивов, отдельные репозитории подключать не нужно.
sudo apt update
sudo apt install fail2ban
# версия и статус демона
fail2ban-client version
systemctl status fail2ban
# что уже включено «из коробки»
sudo fail2ban-client status
В Debian и Ubuntu пакет кладёт файл /etc/fail2ban/jail.d/defaults-debian.conf, в котором джейл sshd уже включён. То есть после установки минимальная защита SSH обычно работает сразу — но проверить это надо руками, а не поверить на слово (см. раздел про backend ниже).
Если вы работаете с systemd-журналом, полезно доустановить биндинги Python к journald — без них backend systemd может не подняться:
sudo apt install python3-systemd
sudo systemctl restart fail2ban
sudo journalctl -u fail2ban -n 50 --no-pager
Раскладка файлов после установки:
/etc/fail2ban/fail2ban.conf— настройки самого демона: уровень логирования, сокет, база банов,dbpurgeage./etc/fail2ban/jail.conf— эталонное описание всех джейлов. Не трогать./etc/fail2ban/jail.d/*.conf— фрагменты конфигурации, подключаются после jail.conf./etc/fail2ban/filter.d/*.conf— фильтры, то есть регулярные выражения./etc/fail2ban/action.d/*.conf— действия: как именно банить (iptables, nftables, отправка письма, вызов API)./var/lib/fail2ban/fail2ban.sqlite3— база активных банов, благодаря ей баны переживают перезапуск демона./var/log/fail2ban.log— собственный лог; на него опирается джейл recidive.
jail.local, jail.d и ключевые параметры
Почему нельзя править jail.conf
jail.conf принадлежит пакету. При любом обновлении fail2ban через apt менеджер пакетов увидит изменённый conf-файл и либо перезапишет его, либо вывалит диалог о конфликте конфигурации, либо оставит .dpkg-dist рядом. В любом сценарии вы теряете либо свои правки, либо новые дефолты пакета.
fail2ban читает конфигурацию слоями: сначала jail.conf, затем jail.local, затем всё из jail.d/ в алфавитном порядке. Более поздний слой переопределяет более ранний, причём по отдельным параметрам, а не по секции целиком. Поэтому в jail.local достаточно перечислить только то, что вы меняете.
sudo tee /etc/fail2ban/jail.local > /dev/null <<'EOF'
[DEFAULT]
# ваши доверенные адреса: локалка, офис, VPN, чекеры мониторинга
ignoreip = 127.0.0.1/8 ::1 203.0.113.0/24
bantime = 1h
findtime = 10m
maxretry = 5
# растущий бан: повторные нарушители сидят дольше
bantime.increment = true
bantime.factor = 2
bantime.maxtime = 7d
banaction = nftables-multiport
[sshd]
enabled = true
mode = aggressive
maxretry = 4
bantime = 1d
EOF
sudo fail2ban-client -t # проверка синтаксиса без применения
sudo systemctl reload fail2ban
Секция [DEFAULT] задаёт значения для всех джейлов; в секции конкретного джейла они переопределяются. Отдельные файлы в jail.d/ удобны, когда конфигурацию раскатывает Ansible или Puppet: один сервис — один файл, без конфликтов при слиянии.
Как подбирать bantime, findtime, maxretry и ignoreip
Смысл параметров простой: если с одного IP за findtime набралось maxretry совпадений фильтра, адрес блокируется на bantime.
- maxretry. Для SSH с ключами — 3–4: легитимный пользователь с правильным ключом вообще не даёт неудачных попыток. Для веб-формы входа, где люди реально забывают пароль, — 5–10, иначе завалите поддержку заявками. Учитывайте, что один заход браузера может дать несколько строк в логе.
- findtime. Окно наблюдения. Слишком маленькое (1–2 минуты) пропускает медленный перебор «по одной попытке в минуту». Разумный диапазон — 10–60 минут. Помните: чем шире окно, тем больше памяти и тем выше шанс поймать человека, который весь день путается в паролях.
- bantime. Час — нормальный старт. Вечный бан (
bantime = -1) выглядит соблазнительно, но раздувает таблицу правил firewall до десятков тысяч записей и рано или поздно ловит легитимный адрес, который вы забудете разбанить. Правильный ответ — не вечный бан, аbantime.increment: каждый следующий бан того же адреса длиннее предыдущего. - ignoreip. Список адресов и подсетей, которые не банятся никогда. Сюда обязательно попадают ваша рабочая сеть, VPN, адреса внутренних чекеров и балансировщиков. Формат — через пробел, поддерживаются CIDR и (в свежих версиях) DNS-имена. Параметр
ignoreself = true, включённый по умолчанию, дополнительно защищает собственные адреса сервера.
Правило подбора: сначала ставьте мягкие пороги и смотрите статистику неделю. Агрессивный
maxretry = 2на публичном сайте — это не безопасность, а генератор инцидентов «клиент не может войти».
Backend: systemd, auto и подводный камень с journald
Параметр backend определяет, откуда джейл берёт события: из текстового файла или из журнала systemd.
auto— fail2ban сам выбирает механизм слежения за файлом: pyinotify, если доступен, иначе периодический опрос. Ключевое слово — файл. Значениеautoне означает «сам найдёт логи где угодно».polling— принудительный опрос файла по таймеру. Медленнее и прожорливее, но работает там, где inotify недоступен (некоторые контейнеры, сетевые ФС).systemd— чтение journald напрямую через API. В этом режимеlogpathигнорируется, а фильтрация записей задаётся директивойjournalmatch.
Теперь самая частая причина «поставил fail2ban, а он не банит». Исторически sshd писал в /var/log/auth.log через rsyslog, и дефолтный джейл рассчитан именно на это. В свежих установках Ubuntu rsyslog может отсутствовать: журналирование целиком отдано systemd-journald, файл /var/log/auth.log не создаётся вовсе. Джейл при этом либо падает с ошибкой о недоступном логе, либо, если файл существует, но пуст (например, остался после апгрейда), тихо работает с нулевым счётчиком.
# есть ли вообще текстовый лог аутентификации
ls -l /var/log/auth.log 2>/dev/null || echo "нет auth.log — логи в journald"
# видит ли journald попытки входа
journalctl -u ssh.service --since "-1h" | grep -i "failed password" | tail
# что говорит сам fail2ban при старте
sudo journalctl -u fail2ban --since "-10m" --no-pager | grep -iE "error|warn|found"
Если логи в журнале — переводим джейл на backend systemd:
sudo tee /etc/fail2ban/jail.d/sshd-systemd.local > /dev/null <<'EOF'
[sshd]
enabled = true
backend = systemd
journalmatch = _SYSTEMD_UNIT=ssh.service + _COMM=sshd
maxretry = 4
bantime = 1d
EOF
sudo fail2ban-client -t
sudo systemctl restart fail2ban
sudo fail2ban-client status sshd
Обратите внимание на имя юнита: в Debian и Ubuntu это ssh.service, во многих RPM-дистрибутивах — sshd.service. Ошибка в journalmatch не вызывает падения — джейл просто не увидит ни одной строки. Проверять надо через fail2ban-regex (см. ниже), а не по отсутствию ошибок в логе.
Признак молчащего джейла: в выводе
fail2ban-client status sshdстрока «Total failed» равна нулю, хотяjournalctlпоказывает десятки «Failed password» за последний час. Это не «атаки прекратились», это неверный источник логов.

Джейл sshd и другие типовые джейлы
Джейл sshd — базовый и почти всегда достаточный минимум. У фильтра sshd есть режимы (mode), которые меняют набор регулярных выражений: normal ловит неудачные пароли и ошибки аутентификации, ddos — обрывы соединений и «пустые» коннекты без попытки логина, aggressive — оба набора сразу, включая обращения с невалидными пользователями и неподдерживаемыми методами. На публичном сервере aggressive обычно оправдан, на сервере с самописными скриптами, которые часто рвут SSH-сессии, — рискован.
| Джейл | Что ловит | Где лог | maxretry | bantime |
|---|---|---|---|---|
sshd | подбор паролей, вход несуществующими пользователями, аномальные обрывы соединений | /var/log/auth.log или journald (ssh.service) | 3–5 | 1 час — 1 сутки |
nginx-http-auth | подбор логина и пароля в HTTP Basic Auth | /var/log/nginx/error.log | 3–5 | 1–6 часов |
nginx-botsearch | перебор путей: админки, .env, бэкапы, чужие CMS | error.log, при желании access.log | 5–10 | 1 сутки |
nginx-limit-req | срабатывания limit_req, то есть превышение частоты запросов | /var/log/nginx/error.log | 10 | 10 минут — 1 час |
postfix, postfix-sasl | подбор SMTP-пароля, попытки релея | /var/log/mail.log или journald | 3–5 | 1 час — 1 сутки |
recidive | адреса, которые уже банились несколькими джейлами | /var/log/fail2ban.log | 3–5 | 1 неделя и больше |
Джейл recidive заслуживает отдельного внимания: он читает не лог сервиса, а собственный лог fail2ban и банит тех, кто уже получал бан несколько раз за сутки. Это дешёвый способ отправить упорных ботов в долгую блокировку, не поднимая порог для обычных пользователей.
[recidive]
enabled = true
logpath = /var/log/fail2ban.log
banaction = %(banaction_allports)s
findtime = 1d
maxretry = 4
bantime = 4w
Действие banaction_allports блокирует адрес не на конкретном порту, а целиком — для рецидивистов это разумно.
fail2ban и nginx: готовые джейлы и свой фильтр
С веб-сервером есть нюанс: большинство штатных nginx-фильтров читают error.log, потому что именно туда nginx пишет отказы Basic Auth и срабатывания limit_req. Коды ответа 401, 403 и 429 в чистом виде живут в access.log, и для них нужен свой фильтр.
[nginx-http-auth]
enabled = true
port = http,https
logpath = /var/log/nginx/error.log
maxretry = 4
bantime = 6h
[nginx-botsearch]
enabled = true
port = http,https
logpath = /var/log/nginx/error.log
maxretry = 6
bantime = 1d
[nginx-limit-req]
enabled = true
port = http,https
logpath = /var/log/nginx/error.log
findtime = 5m
maxretry = 20
bantime = 1h
Джейл nginx-limit-req имеет смысл только вместе с директивами limit_req_zone и limit_req в конфигурации nginx: без них в error.log нечего ловить. Связка «nginx ограничивает частоту, fail2ban банит самых упорных» — рабочая двухступенчатая схема, подробнее о её проектировании — в материале про стратегии ограничения частоты запросов и о методах защиты от DDoS.
Свой фильтр в filter.d и проверка через fail2ban-regex
Допустим, нужно банить адреса, которые массово получают 401 и 429 на API. Пишем фильтр под стандартный combined-формат access.log.
sudo tee /etc/fail2ban/filter.d/nginx-4xx-api.conf > /dev/null <<'EOF'
[Definition]
failregex = ^<HOST> \S+ \S+ \[[^]]+\] "(GET|POST|PUT|PATCH|DELETE) /api/[^"]*" (401|403|429)
ignoreregex =
datepattern = ^[^\[]*\[({DATE})
EOF
Ключевые правила написания фильтра:
<HOST>— обязательный маркер: именно из этой группы fail2ban достаёт IP-адрес. Ровно один на выражение.- Регулярка должна быть якорной (
^) и максимально узкой. Широкое выражение вида.*401.*поймает строку, где 401 — это часть размера ответа или User-Agent, и забанит вам живого клиента. ignoreregex— исключения, которые проверяются после failregex. Удобно, чтобы вывести из-под бана служебные пути вроде/api/health.- Все фильтры лежат в
filter.d/, а джейл ссылается на них по имени файла без расширения.
Теперь главное — проверка. fail2ban-regex прогоняет фильтр по реальному логу и показывает, сколько строк совпало и как разобралась дата.
# фильтр против файла
fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/nginx-4xx-api.conf
# штатный sshd-фильтр против системного журнала
fail2ban-regex systemd-journal /etc/fail2ban/filter.d/sshd.conf
# проверка одной строки (быстрая отладка регулярки)
fail2ban-regex '198.51.100.7 - - [12/Mar/2026:10:00:01 +0300] "POST /api/login HTTP/1.1" 401 12' \
/etc/fail2ban/filter.d/nginx-4xx-api.conf
# подробный разбор: какие строки не подошли
fail2ban-regex --print-all-missed /var/log/nginx/access.log \
/etc/fail2ban/filter.d/nginx-4xx-api.conf
В выводе смотрите на две цифры: Lines: ... matched и Missed lines. Ноль совпадений при заведомо наличии атак означает ошибку в регулярке или в формате даты. Отдельная частая проблема — datepattern: если fail2ban не распознал время строки, он либо считает событие устаревшим, либо игнорирует его. В выводе fail2ban-regex это видно по счётчику «ignored by ... date».
Подключаем фильтр джейлом:
[nginx-4xx-api]
enabled = true
filter = nginx-4xx-api
port = http,https
logpath = /var/log/nginx/access.log
findtime = 5m
maxretry = 25
bantime = 2h

fail2ban-client: статус, разбан и как не забанить себя
Весь оперативный контроль — через fail2ban-client, который общается с демоном по unix-сокету.
# список активных джейлов
sudo fail2ban-client status
# детали одного джейла: счётчики и список забаненных
sudo fail2ban-client status sshd
# разбан конкретного адреса
sudo fail2ban-client set sshd unbanip 198.51.100.7
# разбан во всех джейлах сразу
sudo fail2ban-client unban 198.51.100.7
sudo fail2ban-client unban --all
# ручной бан (например, по данным из внешнего источника)
sudo fail2ban-client set sshd banip 198.51.100.7
# добавить адрес в исключения на лету, без перезапуска
sudo fail2ban-client set sshd addignoreip 203.0.113.10
# перечитать конфигурацию без потери активных банов
sudo fail2ban-client reload
sudo fail2ban-client reload sshd
Теперь про самую популярную аварию — самобан администратора. Сценарий типовой: вы правите джейл, ошибаетесь в фильтре, он начинает ловить обычные успешные подключения, и через минуту ваш IP оказывается в DROP. SSH-сессия при этом чаще всего сохраняется (established-соединение уже разрешено), но новая не установится.
- Всегда добавляйте свой адрес в
ignoreipдо включения новых джейлов. Если адрес динамический — добавьте подсеть провайдера или адрес VPN. - Держите вторую открытую SSH-сессию на время экспериментов. Это бесплатная страховка: даже если новая аутентификация заблокирована, из старой сессии можно выполнить unban.
- Имейте запасной канал доступа: консоль в панели хостинга, KVM или serial console. Если сервер живёт в облаке — например, в Selectel — веб-консоль работает в обход сети и firewall.
- Проверяйте новый фильтр через fail2ban-regex до включения джейла, а не после.
Если доступ всё-таки потерян и есть только консоль, снимите бан вручную:
# посмотреть, где именно висит правило
sudo nft list ruleset | grep -A5 f2b
sudo iptables -S | grep f2b
# аварийно снять все баны
sudo fail2ban-client unban --all
# крайняя мера — остановить демон и почистить цепочки
sudo systemctl stop fail2ban
Подводные камни: firewall, reverse-proxy, logrotate и IPv6
iptables, nftables и ufw
fail2ban не заменяет firewall, а пишет в него. За способ записи отвечает banaction. Основные варианты: iptables-multiport (классика), nftables-multiport (для систем, где нативный firewall — nftables), ufw, firewallcmd-ipset. Смешивать наборы правил вслепую — плохая идея: если система работает на nftables, а fail2ban пишет через прослойку совместимости iptables-nft, правила попадут в отдельные таблицы, и порядок обработки может оказаться не тем, который вы ожидали.
С ufw есть отдельная тонкость: ufw создаёт собственные цепочки, и правила fail2ban должны вставляться перед разрешающими правилами ufw, иначе бан не сработает. Штатное действие ufw учитывает это, а вот самодельные комбинации — часто нет. После настройки всегда проверяйте фактическое состояние правил:
sudo nft list table inet f2b-table 2>/dev/null
sudo iptables -L -n --line-numbers | grep -i f2b
sudo ufw status numbered
Общие принципы укрепления фильтра пакетов и сервисов разобраны в материале про хардненинг веб-сервера.
Reverse-proxy и Cloudflare: банится не тот адрес
Если перед сервером стоит CDN, балансировщик или ещё один nginx, то в логах бэкенда виден IP прокси, а не клиента. fail2ban честно забанит его — и вы отрежете себе весь входящий трафик разом.
Лечится это не в fail2ban, а на веб-сервере: нужно, чтобы $remote_addr восстанавливался из заголовка, который проставляет прокси. Модуль realip подменяет адрес клиента и в access.log, и в записях error.log.
http {
# подсети, которым доверяем проставление заголовка
set_real_ip_from 192.0.2.0/24; # ваш балансировщик
# для CDN перечислите официальные диапазоны провайдера
real_ip_header X-Forwarded-For;
real_ip_recursive on;
}
Доверять
X-Forwarded-Forможно только от явно перечисленных вset_real_ip_fromподсетей. Если разрешить всем, любой клиент подставит чужой адрес в заголовок и заставит fail2ban забанить произвольный IP — от вашего собственного до адресов поисковых роботов. Механика заголовка и модель доверия разобраны отдельно: заголовок X-Forwarded-For.
Второй нюанс: даже с правильным realip бан на уровне firewall самого сервера бесполезен, если трафик всегда приходит от CDN. Блокировать нужно на стороне CDN — через её API. У fail2ban есть действия для внешних API, но их надёжность зависит от лимитов и доступности этого API.
Ротация логов и сброс счётчиков
logrotate переименовывает access.log в access.log.1 и создаёт пустой файл. fail2ban переоткрывает файл по смене inode и продолжает работу, но исторические строки уезжают в архив. Практические следствия:
- Если fail2ban перезапускается (обновление пакета, reload сервиса, перезагрузка), он начинает читать актуальный файл. Сразу после ротации файл пустой, и контекст последних попыток теряется — атакующий получает свежие maxretry попыток.
- Активные баны при этом не теряются: они лежат в sqlite-базе, а срок хранения записей задаёт
dbpurgeageвfail2ban.conf. - Не ставьте
findtimeбольше периода ротации: окно в сутки при ежедневной ротации будет наполовину «слепым». - Для journald проблема не стоит: журнал ротацию по файлам не использует, читается по курсору.
Ограничения при IPv6
Современные версии fail2ban умеют банить IPv6, но с оговорками. Во-первых, нужен banaction, поддерживающий обе версии протокола: nftables работает с inet-таблицей и покрывает оба стека, а классический iptables требует параллельных правил ip6tables. Во-вторых, у провайдера клиент обычно получает целую подсеть /64 и более — бан одного адреса ничего не даёт, атакующий возьмёт следующий из своего же префикса. Часть действий позволяет задать длину префикса для бана, но включать агрессивную блокировку по /64 на публичном сервисе стоит осознанно: под одним префиксом может сидеть много разных пользователей.
Проверить, что джейл вообще видит IPv6, проще всего по фактическому списку банов в fail2ban-client status и по правилам в nftables.

Как проверить настройку и защищённость сервера
Настройка fail2ban проверяется на двух уровнях: внутри сервера — командами выше, снаружи — тем, что реально видит атакующий.
- Какие порты вообще торчат наружу. fail2ban защищает только те сервисы, которые вы включили в джейлы, а закрывать лишнее надо firewall'ом. Внешний скан покажет фактическую картину: проверка открытых портов. Если наружу смотрят СУБД, панель управления или отладочный порт — это важнее любых настроек джейлов.
- Общий скоринг безопасности. Заголовки, TLS, утечки версий и типовые ошибки конфигурации собираются в один отчёт: проверка безопасности сайта. Полезно прогонять после каждого изменения конфигурации веб-сервера.
- Всплеск отказов и падения. Слишком агрессивные джейлы проявляются как рост 4xx, обрывы и недоступность для части пользователей. Внешний мониторинг доступности с уведомлениями ловит и это, и обратную ситуацию — когда сервер лёг под перебором.
- Реакция на срабатывания. Настройте действие с уведомлением (штатные action.d с отправкой письма) или заберите события из
/var/log/fail2ban.logв вашу систему логов. Молчащий fail2ban — это fail2ban, о состоянии которого вы ничего не знаете.
Если по итогам проверки нашлись признаки уже состоявшейся компрометации, порядок действий описан отдельно: что делать, если сайт взломали.
Частые вопросы
Нужен ли fail2ban, если вход по SSH только по ключам?
Строгой необходимости нет: с PasswordAuthentication no подобрать пароль невозможно. Но джейл всё равно полезен — он убирает фоновый шум ботов, снижает число процессов sshd и объём логов. Ставьте мягкие пороги: задача не защита, а гигиена.
Почему fail2ban показывает Currently banned: 0, хотя атаки идут?
Три основные причины по частоте: джейл читает не тот источник (файл вместо journald), фильтр не совпадает с форматом строк, атакующие адреса попали в ignoreip. Диагностика — fail2ban-client status <jail> и fail2ban-regex по реальному логу.
Можно ли банить навсегда?
Технически да, bantime = -1. На практике лучше bantime.increment = true с ограничением bantime.maxtime: правила firewall не разрастаются бесконечно, а рецидивисты всё равно уходят в блокировку на недели. Вечные баны имеет смысл держать отдельным списком, который вы сознательно ревизуете.
Спасёт ли fail2ban от DDoS?
Нет. При объёмной атаке пакеты доходят до сервера и съедают канал и CPU ещё до того, как что-то попадёт в лог. fail2ban работает после записи в лог, то есть уже после обработки запроса. Против DDoS нужны фильтрация на уровне провайдера или CDN и лимиты на уровне nginx.
Как перенести настройки fail2ban на другой сервер?
Копируйте только свои файлы: jail.local, содержимое jail.d/, собственные фильтры из filter.d/ и действия из action.d/. Копировать jail.conf и базу банов не нужно: первый принадлежит пакету и придёт с ним, вторая специфична для конкретной машины.
Сильно ли fail2ban нагружает сервер?
На типовом VPS расход незаметен, пока джейлов немного и логи не гигантские. Проблемы появляются при широком findtime на очень активных access.log и при десятках тысяч правил в firewall. Лечится сужением окна, переходом на ipset/nftables-множества и джейлом recidive вместо вечных банов.
Чеклист внедрения
- Пакет установлен, демон включён в автозапуск,
fail2ban-client statusотвечает. - Все правки — только в
jail.localиjail.d/;jail.confне тронут. - Свой адрес, VPN и адреса мониторинга внесены в
ignoreip. - Проверено, откуда реально пишутся логи sshd; при journald выставлены
backend = systemdи корректныйjournalmatch. fail2ban-client status sshdпоказывает ненулевой счётчик Total failed на публичном сервере.- Каждый собственный фильтр прогнан через
fail2ban-regexс проверкой совпадений и разбора даты. banactionсоответствует реально используемому firewall (iptables / nftables / ufw), правила видны в выводе firewall.- За reverse-proxy или CDN настроен realip с явным списком доверенных подсетей.
- Включён
bantime.incrementили джейлrecidiveвместо вечных банов. - Есть запасной канал доступа к серверу на случай самобана.
- Проведён внешний скан портов и проверка безопасности, настроен внешний мониторинг доступности.
- Отключена парольная аутентификация SSH — главная мера, ради которой fail2ban становится второстепенным.