Оборона продолжается: Fail2ban защищаем веб-сервер от ботов и сканеров




Эта статья является небольшим дополнением к моей предыдущей статье о «настройке защиты сервера инструментами iptables». Так как утилита iptables прекрасно работает на уровне ядра Linux, то для защиты сервера необходим еще один инструмент, который анализирует логи и работает с нарушителями «на лету». На сцену выходит fail2ban. И если iptables выстраивает крепость для защиты нашего домашнего сервера, то fail2ban являет собой бдительного стражника, который отслеживает поведение ботов в реальном времени и оперативно отправляет нарушителей в бан.

Шаг 1. Установка fail2ban в Debian и базовые команды

Поскольку мой домашний сервер работает под управлением Debian, установка этого инструмента займет всего одну минуту. Для этого используется стандартный пакетный менеджер apt.

Обновление списка пакетов и установка самого fail2ban:

sudo apt update
sudo apt install fail2ban

После завершения установки служба автоматически добавится в автозагрузку и запустится в фоновом режиме. Проверить её состояние можно с помощью системного менеджера systemd:

sudo systemctl status fail2ban

Запуск, остановка или перезапуск:

sudo systemctl start fail2ban
sudo systemctl stop fail2ban
sudo systemctl restart fail2ban

Проверка списка активных «тюрем» (jail):

sudo fail2ban-client status

Просмотр подробной информации по конкретной «тюрьме» (например, по защите Nginx):

sudo fail2ban-client status nginx-custom-bad

Шаг 2. Структура конфигурационных файлов jail.local и фильтры

Вся магия fail2ban строится на двух ключевых компонентах: фильтрах (которые ищут нужные строчки в логах по регулярным выражениям) и «тюрьмах» (jail, которые определяют, что делать с нарушителем после того, как фильтр зафиксировал совпадения).

2.1. Где что лежит?

Все стандартные (дефолтные) настройки и фильтры лежат в каталоге /etc/fail2ban/.

Важное правило: Не стоит редактировать файлы с расширением .conf (например, jail.conf). При обновлении пакета через apt они будут перезаписаны. Для кастомных настроек всегда используются файлы с расширением .local. Fail2ban автоматически считывает их и объединяет с дефолтными.

2.2. Создаю собственный фильтр (filter.d)

Фильтр — это текстовый файл с регулярным выражением (failregex), которое указывает fail2ban, какую именно строку в лог-файле нужно считать нарушением.

Создание кастомного фильтра для Nginx, который будет отлавливать ботов-сканеров:

sudo nano /etc/fail2ban/filter.d/nginx-custom-bad.conf

Содержимое файла:

[Definition]
# Регулярное выражение для поиска в логах Nginx
failregex = ^.*access forbidden by rule, client: <HOST>,.*$

ignoreregex =

Это выражение говорит фильтру:

  • ^.* — пропусти любые символы в начале строки (дату, время, уровень ошибки).
  • access forbidden by rule, client: — ищи именно эту фразу (её пишет Nginx при срабатывании защиты).
  • <HOST> — самое главное! Это ключевое слово fail2ban. Оно говорит: «Вместо этого IP-адреса подставь макрос <HOST>, чтобы программа поняла, какой именно IP нужно заблокировать».
  • ,.*$ — пропусти всё остальное, что идет после IP-адреса до конца строки.

2.3. Настраиваю «тюрьму» (jail.local)

Теперь нужно создать саму «тюрьму», которая свяжет мой фильтр, лог-файл и правила наказания.

Создаю или редактирую, если он уже создан, файл конфигурации:

sudo nano /etc/fail2ban/jail.local

Пример моей рабочей конфигурации:

[nginx-custom-bad]
enabled = true
port = http,https
logpath = /var/log/nginx/error.log
filter = nginx-custom-bad
maxretry = 5
findtime = 60
bantime = 3600

Что обозначают параметры этой «тюрьмы»:

  • enabled = true — активирует данную «тюрьму».
  • port = http,https — указывает порты, для которых будут применяться правила блокировки в сетевом фильтре (nftables/iptables).
  • logpath — путь к файлу логов, который мониторит fail2ban (в данном случае — лог ошибок Nginx).
  • filter — имя моего фильтра (nginx-custom-bad), созданного на предыдущем шаге.
  • maxretry = 5 — допустимое количество попыток (срабатываний фильтра).
  • findtime = 60 — интервал времени в секундах (60 секунд), за который должно произойти указанное число попыток (maxretry).
  • bantime = 3600 — время блокировки IP-адреса в секундах (в данном случае — 1 час).

2.4 Важный этап: проверка фильтра.

Перед тем как запускать «тюрьму», крайне полезно проверить, правильно ли фильтр распознает угрозы в логах. Fail2ban предоставляет для этого утилиту fail2ban-regex. Запустить её можно так:

sudo fail2ban-regex /var/log/nginx/error.log /etc/fail2ban/filter.d/nginx-custom-bad.conf

Команда просканирует файл логов и покажет, сколько строк «совпало» (matched) с настроенным регулярным выражением. Если matched равно нулю, значит, либо в логах отсутствуют события попадающие под правила, либо нужно корректировать failregex. Эта команда отлично работает и с архивными логами (например, /var/log/nginx/error.log.1), что полезно, если есть желание проверить фильтр на старых «боевых» данных. Это спасает от ошибок, когда правило написано, но по факту ничего не ловит.

После создания или изменения конфигурационных файлов необходимо перезапустить службу fail2ban, чтобы применить изменения:

sudo systemctl restart fail2ban

Или можно «на лету» перечитать конфигурацию одной командой:

sudo fail2ban-client reload

Это заставит fail2ban обновить настройки всех «тюрем», не прерывая работу текущих блокировок.

Шаг 3. Практический пример: как fail2ban ловит ботов и отправляет их в бан

Чтобы закрепить теорию, отлично подходит реальный пример из жизни моего сервера.

Ситуация следующая: какой-то сканер из интернета начинает активно «щупать» мой сайт, пытаясь найти скрытые файлы конфигурации (например, .env). Nginx успешно пресекает эти попытки с помощью правил доступа и фиксирует это в файле ошибок /var/log/nginx/error.log.

3.1. Что видит fail2ban в логах

Fail2ban отслеживает появление новых строк в файле error.log в реальном времени через системные события ядра (inotify). Как только там появляется вот такая запись:

2026/08/03 16:38:41 [error] 842#842: *1203 access forbidden by rule, client: 45.198.224.25, server: netsurre.ru, request: "GET /.env HTTP/1.1"

Фильтр nginx-custom-bad сверяет эту строку со своим регулярным выражением (failregex). Шаблон успешно совпадает, а вместо <HOST> программа уверенно считывает IP-адрес: 45.198.224.25.

3.2. Реакция стражника

В моей конфигурации (jail.local) задано условие: maxretry = 5 за findtime = 60 (5 срабатываний за 1 минуту).
Злоумышленник не останавливается и продолжает сканирование. Как только счетчик нарушений доходит до пяти, fail2ban переходит к активным действиям:

  • Добавляет IP-адрес 45.198.224.25 в системный журнал.
  • Отдает команду сетевому фильтру (в моем случае nftables) заблокировать этот IP на уровне ядра Linux.

В системном логе fail2ban (/var/log/fail2ban.log) появляется долгожданная запись о бане:

2026-08-03 16:38:51,641 fail2ban.actions        [853]: NOTICE  [nginx-custom-bad] Ban 45.198.224.25

После этого все сетевые пакеты от данного IP-адреса начинают моментально отбрасываться файрволом на уровне ядра. Нарушитель отправляется «отдыхать» на целый час (bantime = 3600), после чего правило автоматически снимается (Unban).

Можно гибко адаптировать параметры fail2ban под особенности своего проекта и интенсивность «шума» в интернете. Все настройки меняются в файле /etc/fail2ban/jail.local. После любых изменений в файле jail.local необходим перезапуск службы или reload.

Шаг 4. Как следить за работой fail2ban

Мало просто настроить защиту, нужно уметь быстро проверить, кто сейчас находится в «тюрьме» и как работают наши правила.

4.1 Общий статус всех «тюрем»

Чтобы увидеть, какие фильтры запущены и сколько IP-адресов сейчас находятся в бане суммарно по всем правилам, используется:

sudo fail2ban-client status

4.2. Детальный разбор конкретной «тюрьмы»

Если необходимо посмотреть список всех заблокированных IP-адресов для настроенного фильтра nginx-custom-bad:

sudo fail2ban-client status nginx-custom-bad

В выводе этой команды увидим:

Status jail: состояние «тюрьмы».
File list: какие файлы логов мониторятся.
Currently banned: количество заблокированных IP прямо сейчас.
IP list: список самих IP-адресов, которые получили бан.

Также можно мгновенно увидеть список последних заблокированных IP, не изучая весь файл логов, воспользуясь быстрой связкой:

sudo tail -n 50 /var/log/fail2ban.log | grep Ban

Команда выведет последние 50 записей системного журнала, оставив только сообщения о банах. Это самый быстрый способ понять, кто «стучался» к нам в последние минуты и получил отпор от стражника.

4.3 Проверка блокировок на уровне ядра (nftables / iptables)

По умолчанию в современных версиях Linux (Debian 12/13) fail2ban работает через подсистему nftables, используя динамические хэш-множества (sets). Проверить список заблокированных IP-адресов в ядре можно командой:

sudo nft list set inet f2b-table addr-set-nginx-custom-bad

Если же в конфигурации (jail.local) явно задан устаревший бэкенд banaction = iptables-multiport, fail2ban создаёт отдельную цепочку в таблице iptables сразу при старте службы. Посмотреть её можно так:

sudo iptables -n -L f2b-nginx-custom-bad

Если используется nftables (дефолт для новых систем), команда iptables выдаст ошибку No chain/target/match by that name, так как цепочки f2b- в iptables в этом случае просто не создаются — фильтрация идёт напрямую через таблицу inet f2b-table.

4.4. Как принудительно разбанить IP

Бывают ситуации, когда мы сами слишком часто ошиблись при вводе данных и попали в бан собственного сервера. Не паникуем! Разблокировать IP вручную можно одной командой:

sudo fail2ban-client set nginx-custom-bad unbanip <IP_АДРЕС>

Это действие мгновенно удалит IP из таблицы блокировки ядра (nftables set), и доступ к серверу будет восстановлен.

4.5. Белый список для своего IP (Whitelist)

Если часто заходить на сервер с одного и того же домашнего или рабочего провайдера, было бы очень обидно случайно «прилететь» в бан из-за нескольких ошибок при вводе пароля или быстрой навигации. Для этого в файле jail.local в секцию [DEFAULT] можно добавить параметр ignoreip:

[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 <МОЙ_ДОМАШНИЙ_IP>

Это гарантирует, что собственный IP-адрес никогда не будет заблокирован стражником, даже при превышении лимита попыток.

Заключение и подведение итогов

Теперь у меня есть дополнительный мощный и надежный защитный контур. На первом этапе iptables выстроил жесткую базовую оборону на уровне ядра Linux, а теперь fail2ban работает как бдительный стражник, который анализирует логи в реальном времени и на лету наказывает зарвавшихся ботов и сканеров.

Такой тандем практически полностью разгружает сервер от лишнего мусора, защищает от перебора и позволяет спокойно развивать проект, не отвлекаясь на постоянные атаки.