Установка и настройка Fail2Ban на Linux VPS
Настройте Fail2Ban для блокировки brute-force атак на SSH и Nginx. Рассмотрены действия бана через UFW и nftables, пользовательские jail, эскалация recidive и тестирование фильтров на Ubuntu 24.04 и Debian 12.
Fail2Ban отслеживает лог-файлы на предмет повторных ошибок аутентификации и блокирует IP-адреса нарушителей через файрвол. Он останавливает brute-force атаки до того, как они увенчаются успехом. Свежеразвёрнутый VPS обычно получает попытки SSH-входа в течение нескольких минут после запуска. Fail2Ban — стандартная защита.
Это руководство охватывает установку на Ubuntu 24.04 и Debian 12, настройку jail для SSH и Nginx, оба бэкенда действий бана (UFW и nftables), jail recidive для рецидивистов и тестирование фильтров с помощью fail2ban-regex. Каждое изменение конфигурации сопровождается шагом проверки.
Необходимые условия: VPS с Ubuntu 24.04 или Debian 12, доступ root или sudo. Файрвол должен быть уже активен, SSH должен быть уже настроен. Это руководство — часть серии безопасность Linux VPS.
Как установить Fail2Ban на Ubuntu 24.04 и Debian 12?
Установите Fail2Ban через apt. Пакет есть в стандартных репозиториях обоих дистрибутивов. Ubuntu 24.04 поставляет версию 1.0.2, Debian 12 тоже. На Debian 12 дополнительно нужен python3-systemd, чтобы Fail2Ban мог читать journal systemd.
sudo apt update && sudo apt install -y fail2ban
На Debian 12 установите Python-привязки для systemd:
sudo apt install -y python3-systemd
Включите и запустите сервис:
sudo systemctl enable --now fail2ban
Флаг enable настраивает автозапуск Fail2Ban при загрузке. Флаг --now запускает его немедленно. Проверьте, что он работает:
sudo systemctl status fail2ban
В выводе должно быть Active: active (running). Если статус показывает failed, смотрите journal:
journalctl -u fail2ban -n 20 --no-pager
В чём разница между jail.conf, jail.local и jail.d/?
jail.conf — конфигурационный файл по умолчанию, поставляемый с пакетом. Обновления пакета перезаписывают его. Никогда не редактируйте jail.conf напрямую. Ваши изменения пропадут при следующем apt upgrade.
jail.local — традиционный файл переопределений. Fail2Ban сначала читает jail.conf, затем накладывает настройки из jail.local. Это работает, но файл разрастается в монолит, который сложно поддерживать.
Каталог jail.d/ — лучший подход. Размещайте один .conf-файл на каждый jail. Fail2Ban загружает их в алфавитном порядке после jail.conf и jail.local. Каждый сервис изолирован, и добавлять или удалять jail можно не трогая остальные конфигурации.
В этом руководстве используются drop-in файлы в jail.d/. Проверьте, что каталог существует:
ls /etc/fail2ban/jail.d/
Он уже должен быть на месте. Если видите файлы вроде defaults-debian.conf — это нормально. На Ubuntu 24.04 этот файл включает jail sshd и задаёт banaction = nftables как действие бана по умолчанию. На Debian 12 он включает jail sshd. Поскольку Fail2Ban загружает файлы из jail.d/ в алфавитном порядке, любой пользовательский файл настроек должен сортироваться после defaults-debian.conf, чтобы переопределить его параметры. Поэтому в руководстве используется zz-defaults.conf.
Как настроить SSH jail в Fail2Ban?
SSH jail отслеживает логи аутентификации и банит IP, которые слишком часто ошибаются при входе. На Ubuntu 24.04 и Debian 12 jail sshd включён по умолчанию через /etc/fail2ban/jail.d/defaults-debian.conf. Но значения по умолчанию мягкие (5 попыток, бан на 10 минут). Ужесточите их.
Создайте drop-in конфигурацию:
sudo tee /etc/fail2ban/jail.d/sshd.conf > /dev/null << 'EOF'
[sshd]
enabled = true
mode = aggressive
port = ssh
backend = systemd
maxretry = 3
findtime = 600
bantime = 3600
EOF
Что означает каждый параметр:
| Параметр | Значение | Описание |
|---|---|---|
enabled |
true |
Активирует этот jail |
mode |
aggressive |
Ловит больше паттернов SSH-ошибок, включая ошибки аутентификации по ключу |
port |
ssh |
Мониторит порт SSH (резолвится в 22 или ваш кастомный порт) |
backend |
systemd |
Читает из journal systemd, а не из лог-файлов |
maxretry |
3 |
Бан после 3 неудачных попыток |
findtime |
600 |
Считает ошибки в окне 10 минут |
bantime |
3600 |
Бан на 1 час (3600 секунд) |
Если вы сменили порт SSH (и правильно сделали), замените ssh на номер порта:
port = 2222
Перезапустите Fail2Ban для применения:
sudo systemctl restart fail2ban
Проверьте, что jail активен:
sudo fail2ban-client status sshd
Ожидаемый вывод:
Status for the jail: sshd
|- Filter
| |- Currently failed: 0
| |- Total failed: 0
| `- Journal matches: _SYSTEMD_UNIT=sshd.service + _COMM=sshd
`- Actions
|- Currently banned: 0
|- Total banned: 0
`- Banned IP list:
строка Journal matches подтверждает, что Fail2Ban читает из journal systemd, а не из файла. Для Ubuntu 24.04 и Debian 12 это правильно.
Как настроить Fail2Ban с UFW в качестве действия бана?
Если вы используете UFW как файрвол, настройте Fail2Ban на вставку правил бана через UFW. Это более простой путь, подходящий для большинства конфигураций.
Создайте файл настроек по умолчанию, задающий UFW как действие бана. Имя zz-defaults.conf выбрано намеренно: на Ubuntu 24.04 пакет поставляет defaults-debian.conf, который задаёт banaction = nftables. Ваш файл должен сортироваться по алфавиту после него, чтобы переопределить это значение.
sudo tee /etc/fail2ban/jail.d/zz-defaults.conf > /dev/null << 'EOF'
[DEFAULT]
banaction = ufw
banaction_allports = ufw
backend = systemd
EOF
Перезапустите и проверьте:
sudo systemctl restart fail2ban
sudo fail2ban-client status sshd
Когда Fail2Ban банит IP, он выполняет ufw insert 1 deny from <IP> to any. Проверьте правила UFW после бана:
sudo ufw status numbered
Вы увидите deny-правила Fail2Ban вверху списка.
Как настроить Fail2Ban на использование nftables вместо iptables?
Для продакшн-серверов, использующих nftables напрямую (без UFW), используйте действие бана nftables-multiport. Fail2Ban создаёт собственную таблицу nftables и управляет правилами бана в ней, не вмешиваясь в ваш существующий набор правил.
Создайте файл настроек по умолчанию. На Ubuntu 24.04 defaults-debian.conf уже задаёт banaction = nftables, так что этот шаг технически необязателен. Но явно указывать — хорошая практика. На Debian 12 этот файл обязателен.
sudo tee /etc/fail2ban/jail.d/zz-defaults.conf > /dev/null << 'EOF'
[DEFAULT]
banaction = nftables-multiport
banaction_allports = nftables[type=allports]
chain = input
backend = systemd
EOF
Перезапустите и проверьте:
sudo systemctl restart fail2ban
sudo fail2ban-client status sshd
Для подтверждения интеграции с nftables выведите список таблиц Fail2Ban:
sudo nft list tables
Должна быть таблица с именем inet f2b-table. После бана можно посмотреть её содержимое:
sudo nft list table inet f2b-table
Сравнение действий бана UFW и nftables
| Аспект | UFW (banaction = ufw) |
nftables (banaction = nftables-multiport) |
|---|---|---|
| Команда бана | ufw insert 1 deny from <IP> |
Добавляет IP в nftables set |
| Где видны правила | ufw status numbered |
nft list table inet f2b-table |
| Поддержка IPv6 | Да (UFW управляет) | Да (семейство inet) |
| Персистентность | Правила UFW сохраняются при перезагрузке | Fail2Ban применяет заново при старте |
| Производительность | Линейный перебор правил | Поиск по множеству (быстрее при большом числе записей) |
| Подходит для | Простые настройки, один сервис | Продакшн, много jail, большое число банов |
Выберите один подход. Не смешивайте действия бана UFW и nftables на одном сервере.
Как добавить свой IP-адрес в белый список Fail2Ban?
Добавьте свой IP в ignoreip, чтобы не забанить самого себя. Это важно. Если вы трижды ошибётесь с паролем, Fail2Ban забанит ваш собственный IP. Вы потеряете доступ по SSH.
Добавьте свой IP в настройки по умолчанию:
sudo tee /etc/fail2ban/jail.d/01-whitelist.conf > /dev/null << 'EOF'
[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 YOUR_IP_HERE
EOF
Замените YOUR_IP_HERE на ваш реальный публичный IP. Узнать его можно командой curl -4 ifconfig.me на локальной машине. Несколько IP указываются через пробел.
Перезапустите и проверьте, что белый список загружен:
sudo systemctl restart fail2ban
sudo fail2ban-client get sshd ignoreip
В выводе перечислены все IP и диапазоны из белого списка. Убедитесь, что ваш IP в списке.
Внимание: если вы подключаетесь с динамического IP, добавление его в белый список даёт ограниченную защиту. Держите под рукой альтернативный способ доступа (консоль через панель хостинг-провайдера) на случай бана.
Как защитить Nginx с помощью пользовательских jail Fail2Ban?
Fail2Ban поставляется с несколькими фильтрами для Nginx. Самые полезные — nginx-http-auth для brute-force на HTTP Basic аутентификации и nginx-botsearch для сканеров, прощупывающих несуществующие пути. Можно также писать собственные фильтры под специфику приложения.
Jail nginx-http-auth
Этот jail банит IP, которые многократно проваливают HTTP Basic аутентификацию. Он читает лог ошибок Nginx.
sudo tee /etc/fail2ban/jail.d/nginx-http-auth.conf > /dev/null << 'EOF'
[nginx-http-auth]
enabled = true
port = http,https
logpath = /var/log/nginx/error.log
maxretry = 3
findtime = 600
bantime = 3600
EOF
Jail nginx-botsearch
Этот jail ловит ботов, сканирующих уязвимые пути (/wp-admin, /phpmyadmin, /.env). Он читает лог доступа Nginx на предмет ответов 404.
sudo tee /etc/fail2ban/jail.d/nginx-botsearch.conf > /dev/null << 'EOF'
[nginx-botsearch]
enabled = true
port = http,https
logpath = /var/log/nginx/access.log
maxretry = 5
findtime = 600
bantime = 7200
EOF
Пользовательский фильтр: бан за чрезмерные 4xx-ошибки
Для приложений за Nginx вы можете захотеть банить IP, генерирующие слишком много 4xx-ошибок. Это ловит credential stuffing, злоупотребление API и перебор путей. Встроенные фильтры это не покрывают, поэтому создайте собственный фильтр.
Создайте файл фильтра:
sudo tee /etc/fail2ban/filter.d/nginx-4xx.conf > /dev/null << 'EOF'
[Definition]
failregex = ^<HOST> - \S+ \[.*\] "[A-Z]+ .+" (400|401|403|404|405) \d+
ignoreregex = ^<HOST> - \S+ \[.*\] "[A-Z]+ /favicon\.ico
^<HOST> - \S+ \[.*\] "[A-Z]+ /robots\.txt
EOF
failregex совпадает со строками лога доступа Nginx, где ответ — код состояния 4xx. ignoreregex исключает типичные ложные срабатывания: запросы favicon.ico и robots.txt.
Создайте jail:
sudo tee /etc/fail2ban/jail.d/nginx-4xx.conf > /dev/null << 'EOF'
[nginx-4xx]
enabled = true
port = http,https
filter = nginx-4xx
logpath = /var/log/nginx/access.log
maxretry = 20
findtime = 600
bantime = 3600
EOF
Повышенный maxretry в 20 не даёт забанить легитимных пользователей, которые при обычном сёрфинге наткнулись на пару 404.
Перезапустите Fail2Ban и проверьте, что все jail загружены:
sudo systemctl restart fail2ban
sudo fail2ban-client status
Ожидаемый вывод со всеми активными jail:
Status
|- Number of jail: 4
`- Jail list: nginx-4xx, nginx-botsearch, nginx-http-auth, sshd
Подробнее о защите Nginx на уровне приложения см. руководство по rate limiting и защите от DDoS в Nginx.
Как тестировать фильтры Fail2Ban с помощью fail2ban-regex?
Перед активацией jail протестируйте его фильтр на реальных логах. Утилита fail2ban-regex прогоняет фильтр по лог-файлу и сообщает о совпадениях. Это предотвращает выкатку фильтра, который ничего не ловит (бесполезен) или ловит всё подряд (банит легитимных пользователей).
Протестируйте пользовательский фильтр nginx-4xx:
sudo fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/nginx-4xx.conf
Пример вывода:
Running tests
=============
Use failregex filter file : nginx-4xx, basedir: /etc/fail2ban
Use log file : /var/log/nginx/access.log
Use encoding : utf-8
Results
=======
Failregex: 42 total
|- #) [# of hits] regular expression
| 1) [42] ^<HOST> - \S+ \[.*\] "[A-Z]+ .+" (400|401|403|404|405) \d+
`-
Ignoreregex: 3 total
Date template hits:
...
Lines: 1842 lines, 0 ignored, 42 matched, 1800 missed
вывод показывает 42 совпадения из 1842 строк. Это разумное соотношение. Если фильтр совпал с 90% строк — regex слишком широкий. Если с 0 строк — либо regex неправильный, либо в логе пока нет 4xx-ошибок.
Посмотреть совпавшие строки:
sudo fail2ban-regex --print-all-matched /var/log/nginx/access.log /etc/fail2ban/filter.d/nginx-4xx.conf
Посмотреть несовпавшие строки (полезно для тюнинга):
sudo fail2ban-regex --print-all-missed /var/log/nginx/access.log /etc/fail2ban/filter.d/nginx-4xx.conf
Протестировать встроенный фильтр sshd против journal systemd:
sudo fail2ban-regex systemd-journal /etc/fail2ban/filter.d/sshd.conf
Как настроить jail recidive для рецидивистов?
Jail recidive следит за собственным логом Fail2Ban. Когда IP банится несколько раз в любом jail, recidive применяет более длительный бан. Это эскалация: первое нарушение — 1 час, рецидивисты — 1 неделя.
На нагруженном продакшн-сервере именно jail recidive реально держит упорных атакующих на расстоянии.
sudo tee /etc/fail2ban/jail.d/recidive.conf > /dev/null << 'EOF'
[recidive]
enabled = true
logpath = /var/log/fail2ban.log
banaction = %(banaction_allports)s
maxretry = 3
findtime = 86400
bantime = 604800
EOF
| Параметр | Значение | Описание |
|---|---|---|
logpath |
/var/log/fail2ban.log |
Резервный путь к логу. С backend = systemd Fail2Ban вместо этого читает свои записи из journal (фильтр recidive имеет встроенную директиву journalmatch) |
maxretry |
3 |
Срабатывает после 3 банов от других jail |
findtime |
86400 |
Смотрит на 24 часа назад (86400 секунд) |
bantime |
604800 |
Бан на 1 неделю (604800 секунд) |
banaction |
%(banaction_allports)s |
Блокирует все порты, а не только тот, что вызвал бан |
Фильтр recidive поставляется с Fail2Ban в /etc/fail2ban/filter.d/recidive.conf. Создавать его не нужно.
Перезапустите и проверьте:
sudo systemctl restart fail2ban
sudo fail2ban-client status recidive
Как мониторить баны и разбанить IP-адрес?
Fail2Ban предоставляет fail2ban-client для всех задач мониторинга и управления. Эти команды работают вне зависимости от бэкенда действий бана.
Проверить общий статус
sudo fail2ban-client status
Выводит все активные jail и их счётчики банов.
Проверить конкретный jail
sudo fail2ban-client status sshd
Показывает текущие забаненные IP, общее число банов и текущие ошибки.
Забанить IP вручную
sudo fail2ban-client set sshd banip 203.0.113.50
Разбанить IP
sudo fail2ban-client set sshd unbanip 203.0.113.50
Если IP был забанен jail recidive, разбаньте его и там:
sudo fail2ban-client set recidive unbanip 203.0.113.50
Проверить, какое действие бана использует jail
sudo fail2ban-client get sshd actions
Перезагрузить конфигурацию без перезапуска
sudo fail2ban-client reload
Читать лог Fail2Ban
journalctl -u fail2ban -f
Это отслеживает лог сервиса Fail2Ban в реальном времени. Вы увидите события бана и разбана по мере их возникновения.
Лог приложения Fail2Ban с деталями банов:
sudo tail -f /var/log/fail2ban.log
Справочник команд fail2ban-client
| Команда | Назначение |
|---|---|
fail2ban-client status |
Вывести все jail |
fail2ban-client status <jail> |
Показать детали jail и забаненные IP |
fail2ban-client set <jail> banip <IP> |
Забанить IP вручную |
fail2ban-client set <jail> unbanip <IP> |
Разбанить IP |
fail2ban-client reload |
Перезагрузить всю конфигурацию |
fail2ban-client reload <jail> |
Перезагрузить один jail |
fail2ban-client get <jail> bantime |
Показать длительность бана |
fail2ban-client get <jail> findtime |
Показать окно подсчёта ошибок |
fail2ban-client get <jail> maxretry |
Показать порог попыток |
fail2ban-client get <jail> ignoreip |
Показать IP в белом списке |
fail2ban-client get <jail> actions |
Показать используемое действие бана |
Сквозная проверка: спровоцировать бан и убедиться, что всё работает
Не надейтесь, что конфигурация работает. Проверьте. Спровоцируйте реальный бан и проверьте всю цепочку: обнаружение в логах, действие бана, правило файрвола и разбан.
Шаг 1: С другой машины (не с вашего IP из белого списка) попробуйте SSH-входы с неверным паролем. После 3 неудач (в соответствии с maxretry) соединение должно быть отклонено.
Если второй машины нет, симулируйте бан через fail2ban-client:
sudo fail2ban-client set sshd banip 198.51.100.25
Шаг 2: Убедитесь, что бан зафиксирован:
sudo fail2ban-client status sshd
Забаненный IP должен появиться в Banned IP list.
Шаг 3: Убедитесь, что правило файрвола создано.
Для UFW:
sudo ufw status numbered | grep 198.51.100.25
Для nftables:
sudo nft list table inet f2b-table
IP должен быть в set внутри таблицы.
Шаг 4: Разбаньте и проверьте удаление:
sudo fail2ban-client set sshd unbanip 198.51.100.25
sudo fail2ban-client status sshd
IP больше не должен быть в списке банов. Проверьте файрвол снова, чтобы убедиться, что правило удалено.
Справочник параметров конфигурации Fail2Ban
| Параметр | По умолчанию | Рекомендуемое | Описание |
|---|---|---|---|
bantime |
10m |
1h или 3600 |
Длительность бана |
findtime |
10m |
10m или 600 |
Окно подсчёта ошибок |
maxretry |
5 |
3 для SSH, 5-20 для веба |
Ошибок до бана |
ignoreip |
127.0.0.1/8 ::1 |
Добавьте свой IP | IP, которые никогда не банятся |
banaction |
nftables (Ubuntu 24.04), iptables-multiport (upstream) |
ufw или nftables-multiport |
Команда файрвола для выполнения |
backend |
auto |
systemd |
Источник логов (journal systemd на современных дистрибутивах) |
destemail |
root@localhost |
Ваш email | Получатель уведомлений |
action |
%(action_)s |
%(action_mwl)s для email-уведомлений |
Действие при бане |
Что-то пошло не так?
Fail2Ban не запускается: проверьте синтаксические ошибки в файлах jail. Пропущенная скобка или невалидное значение помешают запуску.
sudo fail2ban-client -t
Это тестирует конфигурацию без запуска сервиса. Исправьте обнаруженные ошибки.
Jail показывает 0 совпадений, хотя атаки идут: скорее всего, неправильный backend. На Ubuntu 24.04 и Debian 12 используйте backend = systemd. Если стоит backend = auto и в системе нет /var/log/auth.log, Fail2Ban ничего не читает.
Забаненный IP всё ещё может подключаться: действие бана не соответствует вашему файрволу. Если используете UFW — banaction = ufw. Если nftables напрямую — banaction = nftables-multiport. Проверьте, что правило файрвола действительно создаётся после бана.
Вы забанили себя: зайдите на сервер через веб-консоль хостинг-провайдера (VNC/KVM). Оттуда:
sudo fail2ban-client set sshd unbanip YOUR_IP
Или остановите Fail2Ban полностью:
sudo systemctl stop fail2ban
Затем исправьте конфигурацию ignoreip и перезапустите.
Fail2Ban потребляет слишком много памяти: на серверах с большими лог-файлами Fail2Ban может съедать память. Задайте dbpurgeage для ограничения размера базы данных:
sudo tee /etc/fail2ban/jail.d/99-performance.conf > /dev/null << 'EOF'
[DEFAULT]
dbpurgeage = 7d
EOF
Авторское право 2026 Virtua.Cloud. Все права защищены. Данный контент является оригинальным произведением команды Virtua.Cloud. Воспроизведение, повторная публикация или распространение без письменного разрешения запрещены.