Fail2ban давно стал стандартной реакцией на переборы паролей и агрессивные запросы. С переходом экосистемы Linux на nftables логичнее всего направлять баны не в цепочки с десятками отдельных правил, а в наборы (sets). Это экономнее, быстрее и удобнее для отладки. Ниже — пошагово, как связать fail2ban с nftables sets, обеспечить сохранность банов при перезагрузке (persistent), разделить IPv4/IPv6, избежать конфликтов с другими firewall-инструментами и повысить устойчивость к шумным атакам.
Зачем именно nftables sets для fail2ban
Главная идея — хранить забаненные IP в наборах и проверять попадание трафика в эти наборы одной-двумя строчками правил. Это даёт:
- Производительность: одна проверка набора дешевле десятков правил на каждый IP.
- Простоту: баны добавляются и снимаются командами add/delete element без перестройки цепочек.
- Чистоту ruleset: меньше динамики в самих правилах, вся динамика укладывается в содержимое набора.
- Гибкость: отдельные наборы для SSH, HTTP(S), API. Можно использовать разные
bantimeи политику для каждого jail. - Удобство отладки: быстро посмотреть, кто именно в бане, и на сколько.
Важно: fail2ban не предназначен для отражения объёмных DDoS-атак на канальном уровне. Его сила — быстро «гасить» нежелательные IP на уровне хоста: переборы SSH, агрессивные боты к вебу, словари к /wp-login.php и прочее.
Архитектура: таблица, цепочка, наборы
Базовая схема, которой будем придерживаться:
- Таблица
inet filter— единая для IPv4 и IPv6. - Цепочка
inputс policy drop: в начале — проверки наборов на блокировку, затем allow для нужных портов и состояний. - Наборы: по два на каждый сервис —
...-v4(типipv4_addr) и...-v6(типipv6_addr).
Почему два набора? Тип элементов должен соответствовать семейству адресов. Универсальный тип addr поддерживается не на всех комбинациях ядра/инструментов, поэтому в проде безопаснее явно разделить v4/v6.
Если вы поднимаете защиту на новом сервере, удобнее начинать на облачном VDS: там проще управлять ядром, системными службами и firewall без ограничений общего хостинга.

Базовый ruleset nftables (с наборами для fail2ban)
Создадим или обновим /etc/nftables.conf. Пример минималистичного, но безопасного ruleset:
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
set f2b-ssh-v4 {
type ipv4_addr
timeout 12h
comment "Fail2ban SSH v4"
}
set f2b-ssh-v6 {
type ipv6_addr
timeout 12h
comment "Fail2ban SSH v6"
}
set f2b-http-v4 {
type ipv4_addr
timeout 1h
comment "Fail2ban HTTP v4"
}
set f2b-http-v6 {
type ipv6_addr
timeout 1h
comment "Fail2ban HTTP v6"
}
chain input {
type filter hook input priority 0; policy drop
# Падение по наборам — строго в начале
ip saddr @f2b-ssh-v4 drop
ip6 saddr @f2b-ssh-v6 drop
ip saddr @f2b-http-v4 drop
ip6 saddr @f2b-http-v6 drop
# Базовая гигиена
ct state established,related accept
iif lo accept
ip protocol icmp accept
ip6 nexthdr ipv6-icmp accept
# Разрешаем нужные сервисы
tcp dport 22 accept
tcp dport { 80, 443 } accept
# Остальное по умолчанию drop полисой
}
}
Пояснения:
- Сроки
timeoutзадают дефолт для элементов набора. Fail2ban при добавлении IP может переопределять таймаут под конкретный бан. - Строки
dropпо наборам должны стоять раньше любыхacceptпортов, иначе бан не сработает. - Запуск и автозагрузка:
systemctl enable --now nftables. Проверка:nft list ruleset.
Кастомный action для fail2ban: добавляем IP в nftables sets
Стандартный action для nftables умеет сам создавать цепочки и наборы. В этой статье пойдём от обратного: наборы и правила создаём в /etc/nftables.conf, а fail2ban только добавляет/удаляет элементы. Так проще контролировать firewall и добиться persistency.
Создадим файл /etc/fail2ban/action.d/nftset.conf с минимальным набором команд:
[Definition]
# Проверяем, что наборы существуют (v4 и v6)
actioncheck = nft list set <nft_family> <nft_table> f2b-<name>-v4 >/dev/null 2>&1
nft list set <nft_family> <nft_table> f2b-<name>-v6 >/dev/null 2>&1
# При старте/остановке jail ничего не делаем — наборы живут в /etc/nftables.conf
actionstart =
actionstop =
# Бан/разбан: пытаемся и в v4, и в v6. Одна из команд может вернуться с ошибкой — игнорируем.
actionban = nft add element <nft_family> <nft_table> f2b-<name>-v4 { <ip> timeout <bantime>s } 2>/dev/null || true
nft add element <nft_family> <nft_table> f2b-<name>-v6 { <ip> timeout <bantime>s } 2>/dev/null || true
actionunban = nft delete element <nft_family> <nft_table> f2b-<name>-v4 { <ip> } 2>/dev/null || true
nft delete element <nft_family> <nft_table> f2b-<name>-v6 { <ip> } 2>/dev/null || true
[Init]
nft_family = inet
nft_table = filter
Что здесь важно:
- Используем подстановки fail2ban:
<name>— имя jail,<bantime>— время бана в секундах,<ip>— адрес. - Мы не создаём наборы из action — они уже определены в
/etc/nftables.conf. - Команды для v4/v6 дублируются; «лишняя» команда завершится ошибкой и будет проигнорирована благодаря
|| true.
Jail-файлы: SSH и Nginx
Включим jail под SSH с использованием нашего действия. Создадим /etc/fail2ban/jail.d/sshd-nftset.local:
[sshd]
enabled = true
backend = systemd
port = 22
banaction = nftset[name=ssh]
maxretry = 5
findtime = 10m
bantime = 12h
ignoreip = 127.0.0.1/8 ::1
Для Nginx можно включить, к примеру, nginx-http-auth или nginx-botsearch. Создадим /etc/fail2ban/jail.d/nginx-nftset.local:
[nginx-botsearch]
enabled = true
banaction = nftset[name=http]
port = http,https
findtime = 10m
bantime = 1h
maxretry = 10
Под ваш стек фильтры и набор правил могут отличаться. Главное — обеспечить, чтобы в nftables были наборы f2b-http-v4/f2b-http-v6 и строки drop для них стояли первыми в chain input. Для комплексной настройки смотрите также руководство по базовой защите SSH и firewall для VDS и как защитить /wp-login.php c fail2ban и 2FA.
Persistency: что переживёт перезагрузку
Есть два аспекта persistency:
- Правила и наборы — живут в
/etc/nftables.conf. Сервисnftablesзагрузит их при старте. - Содержимое наборов (элементы). По умолчанию, содержимое наборов не сохраняется автоматически между перезагрузками. Однако fail2ban хранит баны в своей базе и при рестарте банит адреса заново, выполняя
actionbanдля активных записей.
Чтобы восстановление работало гарантированно:
- Проверьте, что fail2ban стартует после
nftables(обычно так и есть из коробки). - Убедитесь, что
banactionуказывает на нашnftset. - Установите
dbpurgeageбольше, чем ваш типовойbantime(например,1dили7d), чтобы записи не удалялись из базы слишком рано.
Если требуется именно «заморозить» текущее содержимое наборов (без участия fail2ban), используйте регулярный дамп nft list ruleset с последующим восстановлением. Но практически в проде проще и безопаснее полагаться на штатный механизм fail2ban.
Проверка и отладка
- Статус fail2ban и список jail:
fail2ban-client status. - Статистика по конкретному jail:
fail2ban-client status sshd. - Что в наборах nftables:
nft list set inet filter f2b-ssh-v4,nft list set inet filter f2b-ssh-v6. - Принудительный бан для проверки:
fail2ban-client set sshd banip 198.51.100.10. - Снятие бана:
fail2ban-client set sshd unbanip 198.51.100.10.
Если при старте jail видите ошибки actioncheck, это почти всегда означает, что соответствующие наборы не созданы или названы по‑другому. Сверьте имена наборов в /etc/nftables.conf и аргумент name=... в banaction.

Производительность и масштабирование
Стандартный случай — сотни или тысячи элементов в наборах работают быстрее, чем эквивалентное число правил. На что обратить внимание:
- Размер наборов. Тысячи записей — нормально. Десятки тысяч — тоже, но следите за памятью и временем сборки мусора в ядре (GC для timeout-наборов).
- Порядок правил. Проверки наборов — первее, чем любые разрешающие правила сервисов.
- Сроки бана. Не завышайте
bantimeдо недель без необходимости — наборы будут расти, а поведение частично-блуждающих ботов меняется. - IPv6. Не забывайте про v6-наборы. Сегодня много сканеров уже в IPv6.
Противодействие шумным атакам
Fail2ban — это реакция на события в логах. При «шуме» (например, лавина 404/401/invalid-login) он эффективен. Но от объёмных DDoS (L3/L4) он не спасёт. Что можно добавить на уровне nftables:
- Rate-limit на новые TCP SYN к отдельным портам (ограничивает бурст коннектов).
- Сдерживание UDP-флуда простыми лимитами.
- SYN cookies/SYN proxy там, где уместно (с пониманием нагрузки и совместимости).
Всё это работает совместно с наборами fail2ban: сначала быстро фильтруем злонамеренных клиентов по наборам, затем применяем лимиты для оставшихся. Для HTTPS позаботьтесь о корректном сертификате — при необходимости можно оформить SSL-сертификаты.
Миграция с iptables на nftables
Типичные шаги:
- Переведите системный firewall на nftables. Убедитесь, что инструменты iptables не перехватывают управление (режим iptables-nft совместим, но лучше чистый nft).
- Опишите таблицу
inet filterи наборы в/etc/nftables.conf. - Создайте
action.d/nftset.confи переведите jail наbanaction = nftset. - Понаблюдайте за логами и списком элементов в наборах; после убедитесь, что старые iptables-правила отключены.
Важно не мешать в одном хосте несколько управляющих систем firewall (например, firewalld, ufw и собственный nftables). Выберите одну и придерживайтесь её.
Типичные ошибки и как их избежать
- Баны не работают. Строки
dropпо наборам стоят послеacceptпортов. Решение: поднимите проверки наборов в самый верх. - IPv6 не банится. Нет v6-наборов или нет соответствующих строк
ip6 saddr @set drop. - После перезагрузки баны исчезли. Fail2ban стартовал до nftables или
dbpurgeageслишком мал, и записи удалены из базы. Исправьте порядок и настройки. - Конфликт с firewalld/ufw. Две системы одновременно управляют таблицей/цепочками. Оставьте одну.
- Случайный flush ruleset. При экспериментировании не перезатирайте наборы с продовыми данными. Держите рабочий конфиг в VCS и применяйте обновления командой
nft -f /etc/nftables.conf.
Расширения: общие блок-листы и «рецидивисты»
Подход с наборами отлично масштабируется:
- Сделайте отдельные наборы под «рецидивистов» (например,
f2b-recidive-v4/v6) с большимtimeoutи включите jailrecidiveв fail2ban. - Импортируйте собственные статичные блок-листы в наборы и проверяйте их в том же
chain input. - Для почтовых сервисов смотрите также jail для Postfix и Dovecot — принципы с наборами те же.
Порядок запуска сервисов и резервная копия правил
Проверьте зависимости systemd: nftables.service должен стартовать раньше fail2ban.service. Для надёжности держите актуальную копию правил: периодически сохраняйте nft list ruleset в артефакты CI или в репозиторий с конфигурацией. Для отката достаточно применить сохранённый файл.
Итоги
Связка fail2ban + nftables sets даёт быстрые и управляемые баны без раздувания ruleset. Наборы легко отлаживаются, хорошо переживают перезагрузки при корректном порядке запуска и настройках базы fail2ban, а также масштабируются под разные сервисы и политики. В результате вы получаете компактный, быстрый и предсказуемый firewall-слой, который заметно снижает шум от переборов и агрессивных ботов, не усложняя эксплуатацию.


