
Стандартная установка fail2ban с jail для SSH работает из коробки, но реальная защита начинается с кастомных jail под конкретные приложения. Разберём создание jail для nginx (блокировка по 4xx/5xx), защиту WordPress (xmlrpc.php и wp-login.php), настройку recidive для бана рецидивистов и управление whitelist-ом.
Архитектура fail2ban
Fail2ban состоит из трёх компонентов:
Filter - регулярные выражения для разбора логов (
/etc/fail2ban/filter.d/)Jail - объединяет filter с параметрами (порт, лог, порог срабатывания, время бана)
Action - что делать при бане (iptables, ipset, sendmail и др.)
Цепочка: fail2ban читает лог → filter матчит строки → при достижении maxretry за findtime секунд → выполняется action (добавляет IP в iptables).
Версия fail2ban 1.0.2 установлена в Ubuntu 24.04. Конфиги в /etc/fail2ban/jail.d/ переопределяют дефолтные настройки - редактируйте только их, не трогая /etc/fail2ban/jail.conf.
sudo apt install fail2ban -y
sudo systemctl enable fail2ban
fail2ban-client version
# 1.0.2Базовые настройки по умолчанию
Создаём /etc/fail2ban/jail.d/defaults.conf:
[DEFAULT]
# Время бана в секундах (1800 = 30 минут)
bantime = 1800
# Период поиска нарушений
findtime = 600
# Число нарушений до бана
maxretry = 5
# Backend для чтения логов
backend = auto
# Метод бана (iptables-multiport быстрее ipfw)
banaction = iptables-multiport
# Whitelist - эти IP никогда не банятся
ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24
# Email при бане (если настроен sendmail)
# destemail = admin@example.com
# sendername = Fail2ban
# action = %(action_mwl)sJail для SSH (стандартный, для примера)
[sshd]
enabled = true
port = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s
maxretry = 3
bantime = 3600
findtime = 300Jail для nginx - блокировка по 4xx/5xx
Создаём filter /etc/fail2ban/filter.d/nginx-4xx.conf:
[Definition]
# Матчим все 4xx ответы, кроме 400 и 404 (слишком часты легитимно)
failregex = ^<HOST> -.*"(GET|POST|HEAD|PUT|DELETE).*" (4(?!0[04])\d{2}|5\d{2}) .*$
ignoreregex =
Более строгий вариант - матчить только подозрительные 4xx:
[Definition]
failregex = ^<HOST> -.*"(GET|POST|HEAD).*(\.php|\.asp|\.env|\.git|\.htaccess|wp-config|etc/passwd)" (400|403|404|405|429) .*$
ignoreregex =
Создаём jail /etc/fail2ban/jail.d/nginx-custom.conf:
[nginx-4xx]
enabled = true
port = http,https
filter = nginx-4xx
logpath = /var/log/nginx/access.log
maxretry = 15
findtime = 60
bantime = 600
[nginx-5xx]
enabled = true
port = http,https
filter = nginx-5xx
logpath = /var/log/nginx/access.log
maxretry = 10
findtime = 60
bantime = 1800
Filter для 5xx /etc/fail2ban/filter.d/nginx-5xx.conf:
[Definition]
failregex = ^<HOST> -.*" 5\d{2} .*$
ignoreregex = ^<HOST> -.*" 502 .* "Mozilla.*$
Тестируем filter до перезапуска:
sudo fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/nginx-4xx.conf

Защита WordPress
WordPress атакуют постоянно - брутфорс wp-login.php и xmlrpc.php. Оба endpoint нужно защищать отдельно.
Filter для wp-login.php
/etc/fail2ban/filter.d/wordpress-login.conf:
[Definition]
# Неудачная авторизация WordPress возвращает 200 с ключевыми словами
# Используем лог nginx + специальный формат
failregex = ^<HOST> -.*"POST /wp-login.php.*" 200.*$
# Или через PHP-лог (если доступен)
# failregex = ^<HOST> -.*"POST /wp-login.php" 200
ignoreregex =
Для более точного обнаружения настраиваем Nginx logging с флагом неудачной авторизации. В WordPress добавляем action при неудачном входе через functions.php:
add_action('wp_login_failed', function($username) {
$ip = $_SERVER['REMOTE_ADDR'];
error_log("[wp-fail2ban] Authentication failure for user: $username from $ip");
}, 10, 1);
Тогда filter читает /var/log/php/error.log:
[Definition]
failregex = \[wp-fail2ban\] Authentication failure.* from <HOST>
ignoreregex =Filter для xmlrpc.php
/etc/fail2ban/filter.d/wordpress-xmlrpc.conf:
[Definition]
failregex = ^<HOST> -.*"POST /xmlrpc.php.*" (200|403|405) .*$
ignoreregex =Jail для WordPress
/etc/fail2ban/jail.d/wordpress.conf:
[wordpress-login]
enabled = true
port = http,https
filter = wordpress-login
logpath = /var/log/nginx/access.log
maxretry = 5
findtime = 300
bantime = 7200
[wordpress-xmlrpc]
enabled = true
port = http,https
filter = wordpress-xmlrpc
logpath = /var/log/nginx/access.log
maxretry = 3
findtime = 60
bantime = 86400
XML-RPC атаки часто используют multicall - одним запросом проверяют сотни паролей. Поэтому maxretry = 3 здесь оправдан.
Ещё лучше - закрыть xmlrpc.php полностью в Nginx, если он не используется:
location = /xmlrpc.php {
deny all;
access_log off;
log_not_found off;
}

Jail recidive - бан рецидивистов
Recidive - встроенный jail fail2ban, который банит IP на долгий срок, если они попались в другие jail несколько раз. IP банится на 1 неделю при 5 срабатываниях за 1 день.
/etc/fail2ban/jail.d/recidive.conf:
[recidive]
enabled = true
logpath = /var/log/fail2ban.log
banaction = iptables-allports
filter = recidive
maxretry = 5
findtime = 86400
bantime = 604800
# Логировать баны recidive отдельно
action = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
mail-whois[name=%(__name__)s, dest="%(destemail)s"]
Filter recidive уже включён в стандартную установку. Он читает /var/log/fail2ban.log и матчит строки вида Ban 1.2.3.4.
Убедитесь, что fail2ban пишет логи:
ls -la /var/log/fail2ban.log
# Если нет - создаём:
sudo touch /var/log/fail2ban.log
sudo systemctl restart fail2banIP Whitelist - исключения из всех правил
Whitelist указывается в параметре ignoreip секции [DEFAULT]. Поддерживаются IP, подсети CIDR и DNS-имена.
В /etc/fail2ban/jail.d/defaults.conf:
[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24 10.0.0.0/8 185.10.20.30
Динамическое добавление IP в whitelist без перезапуска:
# Добавить IP во все jail
sudo fail2ban-client set JAIL ignoreip 1.2.3.4
# Для конкретного jail
sudo fail2ban-client set sshd ignoreip 1.2.3.4
Если белый список нужно хранить в файле:
[DEFAULT]
ignoreip = 127.0.0.1/8 ::1
ignorecommand = /usr/bin/grep -cF <ip> /etc/fail2ban/whitelist.txtУправление banами вручную
# Статус всех jail
sudo fail2ban-client status
# Статус конкретного jail
sudo fail2ban-client status nginx-4xx
# Список заблокированных IP
sudo fail2ban-client status nginx-4xx | grep "Banned IP"
# Разблокировать IP
sudo fail2ban-client set nginx-4xx unbanip 1.2.3.4
# Заблокировать IP вручную
sudo fail2ban-client set nginx-4xx banip 1.2.3.4
# Убрать IP из бана во всех jail
for jail in $(sudo fail2ban-client status | awk '/Jail list/{print $NF}' | tr ',' ' '); do
sudo fail2ban-client set $jail unbanip 1.2.3.4 2>/dev/null
done
Проверить, заблокирован ли IP в iptables:
sudo iptables -L f2b-nginx-4xx -n | grep 1.2.3.4Отладка и мониторинг
# Тест filter на логе
sudo fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/nginx-4xx.conf --print-all-missed
# Посмотреть лог fail2ban
sudo tail -f /var/log/fail2ban.log
# Перечитать конфиг без перезапуска
sudo fail2ban-client reload
# Проверить синтаксис всех конфигов
sudo fail2ban-client --test

Итог
Кастомные jail превращают fail2ban из SSH-защитника в полноценный инструмент защиты веб-приложений. Ключевые правила: findtime и maxretry устанавливают чувствительность, bantime - строгость наказания. Для WordPress xmlrpc.php достаточно 3 попыток за минуту. Recidive автоматически находит системных злоумышленников - IP, которые регулярно попадают в разные jail - и блокирует их на неделю без ручного вмешательства.