Настройка fail2ban и автоматическая блокировка брутфорс-атак
Как аккуратно настроить fail2ban через jail.local, запустить джейл sshd на всех четырёх актуальных дистрибутивах LTS, проверить блокировки и снять их, и какие ошибки чаще всего мешают.
Любой сервер с публичным IPv4-адресом уже через несколько минут после первой выдачи начинает получать попытки входа на порт 22. Это не целенаправленная атака, а фоновый шум. fail2ban читает строки журнала с этими неудачными попытками и заставляет файрвол блокировать IP-адрес источника на заданное время. Инструмент есть в пакетах всех рассматриваемых здесь дистрибутивов и настраивается за несколько минут. Подвохи кроются в другом: на Debian 12 fail2ban охотно стартует с ошибкой конфигурации, на некоторых системах он блокирует лишь на первый взгляд, хотя ни один пакет на самом деле не отбрасывается, а одна необдуманная строка в jail.local закроет доступ вам самим.
Эта статья разбирает именно такие места, для Debian 13, Debian 12, Ubuntu 24.04 LTS и Ubuntu 22.04 LTS.
Почему jail.local и никогда jail.conf
Файл /etc/fail2ban/jail.conf принадлежит пакету. При каждом обновлении он может быть перезаписан, и тогда dpkg в лучшем случае задаст вопрос, а в худшем, во время автоматического обновления без присмотра, не спросит вообще. Поэтому ваши изменения живут в /etc/fail2ban/jail.local. После установки этого файла нет, вы создаёте его сами, и в нём должны стоять только те значения, которые вы действительно меняете.
Важен порядок, в котором fail2ban читает файлы. Страница руководства jail.conf(5) называет его явно:
jail.confjail.d/*.confв алфавитном порядкеjail.localjail.d/*.localв алфавитном порядке
Побеждают файлы, прочитанные позже. Конкретно это значит: ваш jail.local перекрывает и настройки из /etc/fail2ban/jail.d/defaults-debian.conf, которые приносит с собой пакет дистрибутива. Многие руководства утверждают обратное и советуют поэтому отдельный файл в jail.d/. Необходимости в этом нет. jail.d/ имеет смысл только тогда, когда вы хотите раскатывать джейлы по отдельности через систему управления конфигурацией.
Что уже задаёт ваш дистрибутив
Самое большое различие между четырьмя системами кроется не в самом fail2ban, а в одном файле, который пакет кладёт в /etc/fail2ban/jail.d/defaults-debian.conf. Посмотрите на него в первую очередь:
cat /etc/fail2ban/jail.d/defaults-debian.conf
| Система | fail2ban | Содержимое defaults-debian.conf |
|---|---|---|
| Debian 13 | 1.1.0 | banaction = nftables, banaction_allports = nftables[type=allports], для [sshd] дополнительно backend = systemd, journalmatch = _SYSTEMD_UNIT=ssh.service + _COMM=sshd и enabled = true |
| Debian 12 | 1.0.2 | только [sshd] и enabled = true |
| Ubuntu 24.04 | 1.0.2 | banaction = nftables, banaction_allports = nftables[type=allports], backend = systemd, плюс [sshd] с enabled = true |
| Ubuntu 22.04 | 0.11.2 | только [sshd] и enabled = true |
Отсюда следует почти всё остальное. Debian 13 и Ubuntu 24.04 с завода читают журнал systemd и блокируют через nftables. Debian 12 и Ubuntu 22.04 откатываются к значениям из jail.conf, то есть к banaction = iptables-multiport и backend = auto. А auto означает явно не «выбери подходящее сам». Комментарий в jail.conf говорит, что auto по очереди пробует pyinotify и polling. Оба способа работают с файлами. Значение auto никогда не выбирает журнал. Без файла /var/log/auth.log sshd-джейл там работает вхолостую.
Установка и первая проверка
apt update
apt install -y fail2ban
На Debian 12 и Ubuntu 22.04 добавляется ещё один пакет, если вы хотите разбирать журнал вместо файла лога:
apt install -y python3-systemd
На Debian 13 python3-systemd входит в жёсткие зависимости пакета и уже присутствует. На Debian 12 он лишь рекомендован, и это самый частый источник ошибок на этой системе. Затем проверьте версию и состояние:
apt-cache policy fail2ban
fail2ban-client --version
systemctl status fail2ban --no-pager
Если здесь уже стоит active (running), половина дела сделана. Если там failed, переходите сразу к разделу про сообщения об ошибках.
Собираем собственный jail.local
Создайте /etc/fail2ban/jail.local. Эта версия работает на всех четырёх системах при условии, что установлен python3-systemd:
[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 203.0.113.7
bantime = 1h
findtime = 10m
maxretry = 5
bantime.increment = true
bantime.factor = 2
bantime.maxtime = 7d
banaction = nftables
banaction_allports = nftables[type=allports]
[sshd]
enabled = true
backend = systemd
port = ssh
maxretry = 4
bantime = 2h
Значение параметров простыми словами: findtime — это скользящее временное окно, maxretry число неудачных попыток внутри него, bantime длительность блокировки. Четыре неудачные попытки за десять минут дают здесь два часа блокировки. Значения времени понимают суффиксы m, h, d и w, а чистое число означает секунды. bantime со значением -1 блокирует навсегда.
Самое интересное здесь bantime.increment. С ним fail2ban удваивает срок блокировки при каждом повторном срабатывании того же адреса, с потолком из bantime.maxtime. Однократная опечатка реального пользователя стоит двух часов, а настойчивый бот через несколько кругов доходит до недели. Эта возможность существует начиная с fail2ban 0.11, то есть доступна и на Ubuntu 22.04. Чтобы она работала и после перезагрузок, база данных должна сохранять историю, а это регулируется параметром dbpurgeage в /etc/fail2ban/fail2ban.conf, по умолчанию одни сутки. Если вы задаёте bantime.maxtime = 7d, поднимите заодно dbpurgeage в файле fail2ban.local.
Два подводных камня в этом блоке. Во-первых, port = ssh: это имя разрешается через /etc/services в порт 22. Если ваша служба SSH слушает на 2222, там должно стоять port = 2222, иначе появится правило файрвола для порта, в который никто не стучится. Во-вторых, ignoreip: впишите туда свой постоянный офисный адрес, но никогда не целую сеть провайдера. И не полагайтесь только на него. Параметр ignoreself и так по умолчанию стоит в true и защищает собственные IP-адреса сервера.
Отличия в зависимости от системы
На Debian 12 у вас есть два равноценных пути. Либо вы остаётесь при backend = systemd и ставите python3-systemd, либо ставите rsyslog, опускаете backend и работаете с /var/log/auth.log. Кроме того, на Debian 12 стоит осознанно задать banaction. Пакет рекомендует nftables или iptables, и apt, как правило, ставит из них только nftables. А значение по умолчанию из jail.conf — iptables-multiport. На минимальной установке fail2ban тогда обращается к бинарнику, которого просто нет.
На Ubuntu 22.04 rsyslog входит в серверный стандарт, файл /var/log/auth.log существует, и джейл работает без вмешательства. Если вы там ничего не хотите перенастраивать, просто не пишите backend и banaction в своём jail.local. fail2ban 0.11.2 хотя и знает действие nftables, но путь через iptables-multiport на этой системе более протоптанный.
На Debian 13 и Ubuntu 24.04 ваш jail.local совпадает с настройками пакета. Вреда от этого нет, конфигурация просто становится явной и потому читаемой.
Применяем и проверяем, что это действительно работает
Перечитать конфигурацию, не теряя действующие блокировки:
fail2ban-client reload
На Debian 12 и Ubuntu 24.04 fail2ban 1.0.2 при запуске и при перечитывании конфигурации выдаёт предупреждение 'allowipv6' not defined in 'Definition'. Оно безобидно, служба продолжает работать нормально.
Команда systemctl restart fail2ban нужна редко и сбрасывает действующие блокировки. Дальше идут запросы состояния:
fail2ban-client ping
fail2ban-client status
fail2ban-client status sshd
Показателен последний вывод. Он показывает Currently failed, Total failed, число блокировок и список заблокированных адресов. Именно здесь заканчивается большинство руководств, и именно здесь начинается проблема: джейл, который чисто стартует и сообщает «0 banned», может быть полностью слепым. Джейл без единого срабатывания выглядит точно так же, как джейл, читающий не тот источник логов.
Три проверки, которые делают эту разницу видимой. Первая: видит ли фильтр эти строки вообще?
fail2ban-regex systemd-journal /etc/fail2ban/filter.d/sshd.conf
При файловом бэкенде вместо этого:
fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf
В конце появляется строка вида Lines: 4211 lines, 0 ignored, 137 matched, 4074 missed. Если там стоит 0 matched, хотя в логе явно видны неудачные попытки, значит не подходит либо фильтр, либо выборка из журнала.
Вторая: какой фильтр журнала джейл использует на самом деле?
fail2ban-client get sshd journalmatch
Ответ различается в зависимости от системы, и это различие важно. Debian 13 сообщает _SYSTEMD_UNIT=ssh.service + _COMM=sshd, а Ubuntu 24.04 наоборот _SYSTEMD_UNIT=sshd.service + _COMM=sshd. То есть там юнит называется sshd.service, а на Debian ssh.service. На Debian 12 и Ubuntu 22.04 в состоянии из коробки возвращается No journal match filter set, потому что там бэкенд systemd не выставлен по умолчанию и джейл читает файл лога. Это не ошибка, а подтверждение того, что фильтра журнала попросту нет. Только с backend = systemd в вашем jail.local на этих системах он становится действующим.
Отдельные условия разделены знаком + и связываются по «или». _SYSTEMD_UNIT=ssh.service + _COMM=sshd подходит, значит, ко всему из юнита ssh.service или к любому процессу с именем sshd. Для встречной проверки в журнале возьмите ровно то имя юнита, которое выдала команда выше:
journalctl -u ssh --no-pager -n 50
journalctl _COMM=sshd --no-pager -n 50
На Ubuntu 24.04 первая строка выглядит соответственно как journalctl -u sshd --no-pager -n 50. Кто возьмёт здесь неверное имя, увидит пустой вывод и будет потом искать не с того конца.
Если здесь появляются строки с Failed password for invalid user, а fail2ban при этом ничего не считает, дело в выборке из журнала. Это становится актуальным, если вы используете OpenSSH из backports или переходите на активацию через сокет. Начиная с OpenSSH 9.8 дочерний процесс называется sshd-session, а не sshd, а при активации через сокет юнит уже не называется ssh.service. Тогда допишите в свой jail.local (на Ubuntu 24.04 с _SYSTEMD_UNIT=sshd.service):
[sshd]
journalmatch = _SYSTEMD_UNIT=ssh.service + _COMM=sshd + _COMM=sshd-session
Третья проверка самая жёсткая. Заблокируйте вручную адрес из диапазона, зарезервированного для документации, и посмотрите, доходит ли он до файрвола:
fail2ban-client set sshd banip 203.0.113.10
Команда отвечает 1, то есть одним заблокированным адресом. Каким инструментом вы подтвердите эту блокировку, зависит от действующего banaction, а он по умолчанию разный в разных дистрибутивах:
| Система | banaction с завода | Проверка активной блокировки |
|---|---|---|
| Debian 13 | nftables | nft list table inet f2b-table |
| Ubuntu 24.04 | nftables | nft list table inet f2b-table |
| Debian 12 | iptables-multiport | iptables -n -L f2b-sshd |
| Ubuntu 22.04 | iptables-multiport | iptables -n -L f2b-sshd |
Более старый Debian 11 ведёт себя при этом как Debian 12. Откуда берётся разница, видно в /etc/fail2ban/jail.d/defaults-debian.conf: только Debian 13 и Ubuntu 24.04 приносят там banaction = nftables, остальные остаются при значении iptables-multiport из jail.conf. Кто не хочет держать это в голове для каждого сервера отдельно, тот прописывает banaction = nftables в собственный jail.local, как в примере выше, и потом везде проверяет через nft.
При действии nftables появляется таблица f2b-table в семействе inet, в ней цепочка f2b-chain с приоритетом filter - 1 и набор с именем addr-set-sshd. Там и должен стоять элемент 203.0.113.10. Цепочки f2b-sshd на этих системах не существует, iptables -n -L f2b-sshd отвечает там No chain/target/match by that name. И наоборот, nft list table inet f2b-table на Debian 12 и Ubuntu 22.04 сообщает Error: No such file or directory, пока там работает iptables-multiport. Оба сообщения не доказывают сломанную конфигурацию, они говорят лишь о неверной команде для выбранного действия.
При действии iptables адрес 203.0.113.10 должен соответственно оказаться в цепочке f2b-sshd. Только когда адрес появляется в файрволе, цепочка от строки лога до отброшенного пакета замкнута. Прибраться за собой не забудьте.
Как снять блокировку
Освободить один адрес из конкретного джейла:
fail2ban-client set sshd unbanip 203.0.113.10
Адрес сразу из всех джейлов:
fail2ban-client unban 203.0.113.10
И в экстренном случае всё в ноль:
fail2ban-client unban --all
Последняя команда — это то, что вам нужно, если вы закрыли доступ самому себе и сидите за аварийной консолью сервера. Она снимает все блокировки без перезапуска службы. Если до сервера уже совсем не достучаться, поможет только путь через консоль в личном кабинете. На KVM root-серверах и выделенных серверах KernelHost вы получаете там сессию VNC, которая работает независимо от SSH. Это же и причина, по которой bantime = -1 не стоит ставить на сервере без второго пути доступа.
Блокировка, которую вы сняли, немедленно вернётся, если неудачные попытки в текущем окне ещё учитываются. Поэтому unban снимает заодно и связанные с адресом неудачные попытки. Кто должен оставаться свободным постоянно, тому место в ignoreip, а следом fail2ban-client reload.
Взаимодействие с UFW и nftables
Здесь возникает ущерб, который заметить труднее всего, ведь fail2ban бодро продолжает сообщать о блокировках, пока пакеты идут насквозь.
UFW — это фронтенд для iptables. При запуске или перечитывании он заново пишет таблицу filter через iptables-restore. При этом созданные fail2ban цепочки исчезают без замены, а сам fail2ban их обратно не создаёт. Поэтому после каждого ufw enable, ufw disable или ufw reload действует правило: systemctl restart fail2ban. До этого момента в fail2ban-client status sshd будет длинный список заблокированных адресов, из которых на деле не блокируется ни один.
Чище будет позволить fail2ban блокировать напрямую через UFW. Действие лежит в /etc/fail2ban/action.d/ufw.conf и входит во все четыре дистрибутива. В jail.local:
[DEFAULT]
banaction = ufw
banaction_allports = ufw
Тогда блокировки попадают правилами в сам UFW и переживают его перезагрузку. Проверка:
ufw status numbered
Заблокированные адреса появляются там как DENY IN в самом верху списка. Важно, чтобы правила блокировки стояли перед вашим разрешением для порта 22, иначе первым сработает разрешение. Поэтому штатное действие вставляет их в начало через insert.
У тех, кто не использует UFW и вместо этого ведёт собственный набор правил в /etc/nftables.conf, есть родственная проблема. Строка flush ruleset в начале этого файла, которую предлагает стандартный шаблон, при перечитывании удаляет и f2b-table. Либо вы отказываетесь от глобального flush и очищаете только свою таблицу, либо привязываете перезапуск fail2ban к службе nftables. Преимущество собственной таблицы fail2ban в том, что с приоритетом filter - 1 она срабатывает раньше обычной таблицы filter, а значит и раньше правил из iptables-nft.
Не стоит смешивать banaction = nftables и собственный набор правил iptables в расчёте на то, что iptables -L покажет блокировки. Оба пути работают параллельно, но каждый инструмент показывает только свой набор правил. Проверяйте всегда тем инструментом, который соответствует настроенному banaction.
Сообщения об ошибках дословно и что за ними стоит
Логи находятся, в зависимости от системы, в двух местах:
journalctl -u fail2ban --no-pager -n 100
tail -n 100 /var/log/fail2ban.log
Failed during configuration: Have not found any log file for sshd jail
Фирменное сообщение Debian 12. Джейл работает с backend = auto, ищет /var/log/auth.log, а файла нет, потому что rsyslog не установлен и всё попадает в журнал. Служба вообще не стартует, systemctl status fail2ban показывает Failed with result 'exit-code'. Два решения: либо apt install -y rsyslog и один перезапуск, либо строка backend = systemd в jail.local под [sshd]. Второй путь современнее, но требует следующего пакета.
Backend 'systemd' failed to initialize due to No module named 'systemd'
Вы задали backend = systemd, но не хватает привязки Python к журналу. На Debian 12 python3-systemd только рекомендован и при установке без рекомендованных пакетов не подтягивается. Решение:
apt install -y python3-systemd
systemctl restart fail2ban
Failed to access socket path: /var/run/fail2ban/fail2ban.sock. Is fail2ban running?
Клиент не достучался до сервера. В подавляющем большинстве случаев служба просто не работает, потому что упала на ошибке конфигурации. Сначала читайте systemctl status fail2ban, потом журнал. Реже после жёсткого обрыва остаётся осиротевший файл сокета, и тогда при запуске сервер сообщает Server already running. В этом случае удалите файл сокета и запустите заново.
NOK: ('sshd',)
Ответ на fail2ban-client status sshd, когда такого джейла во время работы нет. Либо не хватает enabled = true, либо вы опечатались в имени, либо синтаксическая ошибка выше в jail.local проглотила эту секцию. Какие джейлы действительно работают, показывает fail2ban-client status. А что fail2ban собрал из всех файлов, показывает выгрузка конфигурации:
fail2ban-client -d
Error banning и iptables not found
Джейл считает корректно, но блокировка спотыкается о действие. Типично для минимальных установок Debian 12, где присутствует только nftables, тогда как по умолчанию задано iptables-multiport. Либо доставьте пакет через apt install -y iptables, либо переключитесь в jail.local на banaction = nftables. Второй путь — тот, которым Debian 13 и Ubuntu 24.04 и так идут сами.
Если ничего не помогает: упорядоченный откат
Поскольку все изменения лежат в jail.local, путь назад короткий. Отложить файл в сторону, перезапустить службу, и вы снова при настройках пакета:
mv /etc/fail2ban/jail.local /root/jail.local.bak
systemctl restart fail2ban
fail2ban-client status
Если так всё работает, ошибка сидит в вашей конфигурации, и вы возвращаете блоки по одному. Если и так не работает, дело в окружении, то есть в отсутствующем источнике логов или в отсутствующем инструменте файрвола. Именно поэтому jail.conf должен оставаться нетронутым: этот откат за десять секунд возможен только до тех пор, пока файл пакета находится в исходном состоянии.
Напоследок оценка места. fail2ban снижает шум в логах и останавливает медленные повторяющиеся попытки входа. Серьёзная атака из крупного ботнета использует каждый адрес лишь однажды и проходит мимо любого ограничения частоты. Более действенным шагом против подбора паролей по SSH остаётся отключение входа по паролю в пользу ключей. А против объёмных атак в любом случае помогает только фильтрация в сети, у нас это 3,2 Тбит/с фильтрации Arbor в реальном времени прямо в дата-центре во Франкфурте-на-Майне и до 17 Тбит/с глобальной мощности фильтрации в тарифах Professional. fail2ban — это слой ниже, на самом хосте, и там он надёжно выполняет свою задачу, как только сходятся три вещи: правильный источник логов, правильное действие файрвола и jail.local, который вы в случае сомнений уберёте одним движением.
Частые вопросы
Действительно ли нужно оставлять jail.conf нетронутым?
Почему fail2ban на Debian 12 не стартует после установки?
Что именно означает backend = auto?
Как снять блокировку?
Почему fail2ban блокирует, а атакующий всё равно проходит?
По чему видно, что fail2ban действительно работает?
Заменяет ли fail2ban защиту от DDoS?
2026 KernelHost GmbH. Все права защищены. Эта инструкция охраняется авторским правом. Публикация на других сайтах, в том числе частично или в изменённом виде, без нашего письменного согласия не разрешается. Цитирование с указанием источника и активной ссылкой мы приветствуем.

