Обучение · Linux / VPS / Безопасность
Любой VPS с белым IP-адресом начинают сканировать боты в первые минуты после запуска. Чаще всего это автоматический перебор паролей к SSH, а если на сервере есть сайт — то и перебор форм входа: /wp-login.php, /login, панели администратора. Один прочитанный auth.log быстро показывает картину: сотни попыток входа с чужих IP-адресов каждый день.
Fail2ban не заменяет ключи SSH и надёжные пароли, но снижает нагрузку от брутфорса и закрывает источник шума в логах: он следит за файлами логов, находит признаки неудачных попыток входа и на время блокирует IP-адрес через firewall. В этом руководстве настроим Fail2ban на Ubuntu для защиты SSH, разберём разницу между iptables и nftables при бане, добавим фильтр для формы входа на сайте за Nginx и покажем, как проверять и снимать баны, не заблокировав самого себя.
Как устроен Fail2ban
Fail2ban состоит из трёх связанных частей.
Для сайтов, ботов и pet-проектов можно использовать Beget: виртуальный хостинг от 420 ₽/мес., VPS от 330 ₽/мес. и тестовый период.
- Filter — регулярное выражение, которое ищет в логе строку неудачной попытки входа. Для SSH это, например, строки вида
Failed password for ... from <HOST>в/var/log/auth.log. - Jail — правило, которое связывает фильтр с логом, лимитами (
maxretry,findtime) и действием при срабатывании. - Action — команда, которая реально блокирует адрес: добавляет правило в nftables/iptables, дёргает
firewalld, либо просто отправляет письмо.
Демон fail2ban-server перечитывает логи, а fail2ban-client — консольная утилита для управления: статус jail’ов, ручной бан и разбан IP.
Что нужно перед установкой
- VPS с Ubuntu и пользователем с правами
sudo; - уже настроенный вход по SSH-ключу — Fail2ban дополняет эту защиту, а не заменяет её (если ключи ещё не настроены, сначала используйте руководство по безопасному SSH);
- понимание, какой firewall-бэкенд использует сервер — iptables или nftables (это важно для шага с
banaction, см. ниже); - отдельный SSH-сеанс на всякий случай: изменения firewall-правил не должны обрываться на середине.
Проверьте, что сейчас использует ядро для фильтрации:
sudo iptables -V
sudo nft --version
sudo update-alternatives --display iptables 2>/dev/null
На Ubuntu 20.04+ и Debian 11+ по умолчанию используется nftables, но пакет iptables может присутствовать как совместимая обвязка (iptables-nft). Это определяет, какой banaction понадобится Fail2ban дальше.
Устанавливаем Fail2ban
sudo apt update
sudo apt install fail2ban
sudo systemctl enable --now fail2ban
sudo systemctl status fail2ban --no-pager
Если сервис не стартовал, причину обычно видно сразу в журнале:
sudo journalctl -u fail2ban --no-pager -n 50
Создаём jail.local вместо правки jail.conf
Конфигурация читается в таком порядке, и каждый следующий файл переопределяет предыдущий:
/etc/fail2ban/jail.conf
/etc/fail2ban/jail.d/*.conf
/etc/fail2ban/jail.local
/etc/fail2ban/jail.d/*.local
jail.conf обновляется вместе с пакетом, поэтому правки в нём теряются при апдейте. Стандартный подход — скопировать его в jail.local и менять уже копию:
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.local
В jail.local не обязательно оставлять все секции — достаточно указать только то, что вы хотите переопределить.
Настраиваем секцию [DEFAULT]
Основные параметры, которые стоит проверить в блоке [DEFAULT]:
[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 203.0.113.10
bantime = 1h
findtime = 10m
maxretry = 5
backend = systemd
ignoreip— список адресов, которые никогда не банятся. Обязательно добавьте сюда свой текущий рабочий IP, иначе рискуете забанить самого себя после нескольких опечаток в пароле.bantime— на сколько блокируется адрес. По умолчанию 10 минут; для боевого сервера обычно ставят от часа и выше. Отрицательное значение (bantime = -1) означает бан навсегда.findtime— окно, в котором считаются неудачные попытки.maxretry— сколько попыток допустимо в пределахfindtime, прежде чем сработает бан.backend = systemd— использовать journald вместо чтения текстового файла лога; актуально, еслиrsyslogне пишет/var/log/auth.logв вашем образе Ubuntu. Если файл лога на месте, можно оставитьbackend = auto.
После правки конфигурации перезапустите сервис и проверьте, что синтаксис верный:
sudo fail2ban-client -d # тест конфигурации без применения
sudo systemctl restart fail2ban
sudo fail2ban-client status
Включаем защиту SSH
В jail.local найдите или добавьте секцию [sshd]:
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = %(sshd_log)s
backend = %(sshd_backend)s
maxretry = 4
findtime = 10m
bantime = 1h
Если SSH слушает нестандартный порт, замените port = ssh на конкретный номер — иначе Fail2ban будет банить IP в firewall, но правило будет применяться не к тому порту, который реально атакуют.
Примените изменения и проверьте статус jail’а:
sudo systemctl restart fail2ban
sudo fail2ban-client status sshd
Вывод должен показать, сколько попыток зафиксировано и сколько адресов забанено:
Status for the jail: sshd
|- Filter
| |- Currently failed: 2
| |- Total failed: 37
| `- Journal matches: ...
`- Actions
|- Currently banned: 1
|- Total banned: 6
`- Banned IP list: 203.0.113.42
nftables или iptables: от этого зависит banaction
Здесь чаще всего ошибаются: Fail2ban по умолчанию рассчитан на iptables-действия (banaction = iptables-multiport), но современные Ubuntu и Debian используют nftables как основной бэкенд. Если оставить действие по умолчанию на системе, где нет классического iptables, попытка бана в логе Fail2ban может завершиться ошибкой действия, а сам бан — не примениться.
Fail2ban поставляется со встроенными nftables-действиями:
nftables(алиасnftables-multiport) — банит по конкретным портам, использует nftablessetдля хранения адресов;nftables-allports— банит адрес полностью, по всем портам.
Чтобы переключиться на nftables, в [DEFAULT] укажите:
[DEFAULT]
banaction = nftables-multiport
banaction_allports = nftables-allports
После смены banaction перезапустите Fail2ban и проверьте, что таблица и набор адресов реально созданы:
sudo systemctl restart fail2ban
sudo nft list tables
sudo nft list set inet f2b-table addr-set-sshd
Если сервер работает через firewalld (характерно для RHEL/Rocky/Fedora, реже — для управляемых Ubuntu-образов), вместо nftables-действий обычно используют firewallcmd-multiport и firewallcmd-allports — уточняйте активный бэкенд командой firewall-cmd --state, если пакет установлен.
Проверяем фильтр до того, как он начнёт банить
Прежде чем полагаться на новый или изменённый фильтр, прогоните его по реальному логу через fail2ban-regex — это безопасный тест без применения бана:
sudo fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf
В выводе fail2ban-regex покажет число совпадений и несколько примеров строк. Если совпадений ноль, а атаки в логе точно есть, проблема обычно в logpath или в backend — например, дистрибутив пишет логи только в journald, а logpath указывает на пустой файл.
Защищаем форму входа на сайте за Nginx
Fail2ban одинаково хорошо работает с логами веб-сервера, если запросы там различимы. Частый сценарий — перебор /wp-login.php или собственной формы /login. Сначала убедитесь, что Nginx вообще фиксирует такие запросы в отдельном access-логе — так фильтру проще, а Fail2ban не нужно парсить общий лог всех сайтов на сервере.
Создайте фильтр /etc/fail2ban/filter.d/nginx-login.conf:
[Definition]
failregex = ^<HOST> -.*"(POST|GET) /(wp-login\.php|login)(/)?.*" (200|401|403)
ignoreregex =
И jail в jail.local:
[nginx-login]
enabled = true
filter = nginx-login
port = http,https
logpath = /var/log/nginx/example.com.access.log
maxretry = 5
findtime = 10m
bantime = 1h
banaction = nftables-multiport
Код ответа 200 в фильтре может показаться странным, но именно так часто выглядит неудачная попытка входа в WordPress и многих самописных формах — сервер отвечает 200 OK с HTML-страницей ошибки, а не HTTP-кодом ошибки. Проверьте это на своём сайте: посмотрите реальные строки лога для неудачного логина и подстройте failregex под фактический формат, прежде чем включать jail в бой. Правило «одна попытка — одна строка лога» работает не для всех фреймворков: некоторые логируют только успешный вход, и тогда придётся смотреть на уровень приложения, а не Nginx.
Проверка фильтра на реальном логе — тот же принцип, что и для SSH:
sudo fail2ban-regex /var/log/nginx/example.com.access.log /etc/fail2ban/filter.d/nginx-login.conf
sudo systemctl restart fail2ban
sudo fail2ban-client status nginx-login
Если сайт уже стоит за reverse proxy, убедитесь, что в access-логе Nginx пишется реальный IP клиента, а не адрес прокси перед ним — иначе Fail2ban будет банить не того, кого нужно. Логика передачи X-Forwarded-For и настройка доверенных прокси разобраны в статье про Nginx reverse proxy для Docker-приложения.
Ручной бан, разбан и просмотр списка
Иногда бан нужно снять вручную — например, если под фильтр попал легитимный адрес:
sudo fail2ban-client set sshd unbanip 203.0.113.42
sudo fail2ban-client set sshd banip 198.51.100.7
sudo fail2ban-client status sshd
Список всех активных jail’ов:
sudo fail2ban-client status
Если нужно временно отключить jail целиком, не удаляя конфигурацию:
sudo fail2ban-client stop
или для одного jail — установить enabled = false в jail.local и перезапустить сервис.
Диагностика: если бан не срабатывает
-
Проверьте, что jail включён и видит попытки.
sudo fail2ban-client status sshdЕсли
Currently failedне растёт при заведомо неудачных попытках входа — проблема вlogpath/backend, а не в действии бана. -
Проверьте сам лог Fail2ban.
sudo tail -n 100 /var/log/fail2ban.logСтроки
NOTICE [sshd] Ban 203.0.113.42подтверждают, что бан выполнен на уровне Fail2ban. Если такой строки нет — не дошло до действия, смотрите фильтр. -
Проверьте, что правило реально появилось в firewall.
sudo nft list set inet f2b-table addr-set-sshd # или для iptables-варианта: sudo iptables -L f2b-sshd -nЕсли в логе Fail2ban есть
Ban, а в firewall правила нет — почти всегда это несовпадениеbanactionс реальным бэкендом (iptables-действие на системе с nftables, или наоборот). - Не тестируйте бан на своём единственном SSH-сеансе. Оставляйте одно открытое соединение и проверяйте
maxretryиз другого источника — второй SSH-сессии, VPN или мобильного интернета.
Чек-лист перед тем, как доверять Fail2ban
- в
ignoreipдобавлен ваш рабочий IP-адрес; banaction/banaction_allportsсоответствуют реальному firewall-бэкенду сервера (nftables или iptables);- фильтр SSH проверен через
fail2ban-regexна живом логе; - для веб-фильтров есть отдельный access-лог сайта и подтверждено, что в нём виден реальный IP клиента;
fail2ban-client status <jail>показывает растущий счётчикfailedпри тестовых неудачных попытках;- после бана правило действительно видно в
nft list setилиiptables -L; bantime,findtime,maxretryосознанно выбраны под конкретный сервис, а не оставлены по умолчанию вслепую;- есть способ зайти на сервер помимо основного SSH-сеанса, если что-то пойдёт не так.
FAQ
Fail2ban защищает от DDoS?
Нет. Fail2ban реагирует на записи в логах аутентификации и по своей природе рассчитан на брутфорс входа, а не на объёмные атаки на сетевом уровне. От DDoS нужны другие механизмы — на уровне провайдера, CDN или отдельного firewall перед сервером.
Можно ли использовать Fail2ban вместе с UFW?
Да. UFW сам по себе — обвязка над iptables/nftables и не мешает Fail2ban добавлять свои правила бана. Убедитесь только, что banaction соответствует тому бэкенду, который реально активен (см. раздел про nftables и iptables выше).
Почему в логе Fail2ban есть «Ban», а подключение с забаненного IP всё равно проходит?
Чаще всего либо banaction не совпадает с активным firewall-бэкендом, либо правило добавляется в цепочку/таблицу, которая не подключена к реальному пути пакета — например, кастомный nftables-конфиг перекрывает таблицу Fail2ban собственными правилами с более высоким приоритетом. Проверяйте nft list ruleset целиком, а не только таблицу Fail2ban.
Что лучше — растущий bantime или фиксированный?
Для интерактивных сервисов вроде SSH многие используют bantime.increment = true, чтобы повторные нарушения банились на всё более долгий срок. Это снижает эффект от адресов, которые ждут окончания короткого бана и пробуют снова. Настройка описана в официальной документации jail.conf.
Официальная документация
- Fail2ban GitHub — исходный код и wiki — актуальные фильтры, действия и issue-трекер по конкретным версиям.
- Fail2ban Wiki: nftables actions — использование
nftables/nftables-allportsи миграция с iptables. - Debian Wiki: Fail2ban — установка и особенности на Debian/Ubuntu.
- manpage jail.conf(5) — полное описание параметров
bantime,findtime,maxretry,backend,banaction.
Нужна помощь с настройкой firewall и безопасности VPS?
Проверим SSH, firewall, Fail2ban, обновления и журналы сервера. Аудит — от 9 900 ₽.
Бесплатное руководство «Безопасный Linux/VPS»
14 практических страниц: SSH, firewall, обновления, резервные копии, WordPress, Docker и действия при признаках взлома.
Подборка онлайн-курсов для разработчиков — Python, Java, веб и DevOps.
14 практических страниц: SSH, firewall, обновления, резервные копии, WordPress, Docker и действия при признаках взлома.
Проверим SSH, firewall, обновления, резервные копии, Docker и журналы. Аудит — от 9 900 ₽.
Статья может содержать партнёрские ссылки. Это не влияет на стоимость для вас, но помогает развивать блог.
