OSEN-НИЙ SAAALEСкидка 50% на виртуальный хостинг и VDS
до 30.11.2025 Подробнее
Выберите продукт

fail2ban для почты: точные jails для Postfix и Dovecot

Почтовые серверы ежедневно получают bruteforce. Показываю, как настроить fail2ban для Postfix и Dovecot без ложных банов: точные фильтры по аутентификации, отдельные jails для submission/SMTPS и IMAP/POP3, проверка через fail2ban-regex и отладка.
fail2ban для почты: точные jails для Postfix и Dovecot

Если у вас свой почтовый сервер на Postfix и Dovecot, то вы почти наверняка видите в логах попытки bruteforce: сотни неудачных входов на IMAP/POP3 и бесконечные пробные авторизации на submission/SMTPS. fail2ban отлично гасит такие волны, но у почты есть риск «перебанить лишнее»: слишком агрессивные фильтры могут блокировать внешние MX-сервера или клиентов с нестабильным соединением. Ниже — практическая схема точных jails и фильтров, которые ловят только реальный bruteforce авторизации и минимизируют ложные срабатывания.

Зачем разделять jails для почты

Почтовая подсистема состоит из разных ролей и портов:

  • Postfix: публичный SMTP на 25 порту (входящая почта), а также клиентские submission/SMTPS на 587/465 для аутентифицированной отправки.
  • Dovecot: IMAP/POP3 (обычно 143/110) и их TLS-варианты 993/995 для чтения почты пользователями.

Ошибка многих конфигураций — использовать один общий jail для всего Postfix и банить по любому reject или «lost connection». Это приводит к блокировке легитимных внешних хостов, пытавшихся доставить письмо (в это время MTA вполне корректно отвергает спам). Правильный подход — бить по точным признакам неудачной аутентификации и разделять jails:

  • postfix-submission — неудачные SASL-авторизации на 587/465.
  • dovecot-auth — неудачные логины на IMAP/POP3.
  • recidive-mail — «долгоиграющий» бан для IP, который системно попадает под баны снова и снова.

Идея простая: не баним за отказ в приёме письма на 25 порту (там много легитимного шума), а баним только за постоянные провалы авторизации.

Логи и backend: systemd-journald vs файлы

Современные дистрибутивы всё чаще хранят почтовые логи в journald. Для fail2ban это означает удобный backend = systemd и возможность точно фильтровать по SYSLOG_IDENTIFIER (например, postfix/submission/smtpd) без хрупких регулярных выражений таймстампов.

Если у вас классическая схема с rsyslog, логи обычно в /var/log/mail.log (Debian/Ubuntu) или /var/log/maillog (RHEL/AlmaLinux/Rocky). Оба варианта рабочие, но с journald проще сделать «ювелирные» jails.

Установка и базовая структура

На большинстве систем установка стандартная. Примеры для Debian/Ubuntu и RHEL-подобных:

apt update
apt install fail2ban

yum install fail2ban
dnf install fail2ban

systemctl enable --now fail2ban

Конфигурацию удобнее вести в /etc/fail2ban/jail.d/ своими файлами, а фильтры — в /etc/fail2ban/filter.d/. Так вы не потеряете настройки при обновлении пакета. Если вы поднимаете почтовик на отдельном VDS, сразу продумайте файрвол на уровне хоста и провайдера.

Конфигурация jails fail2ban для Postfix и Dovecot в терминале

Точный jail для Postfix: только submission/SMTPS

Наша цель — реагировать только на неудачные SASL-логины клиентов, а не на все события Postfix. Это достигается двумя вещами:

  1. Фильтр, ловящий именно «SASL authentication failed»;
  2. journalmatch, ограничивающий источник логов процессами postfix/submission/smtpd и postfix/smtps/smtpd.

Создайте фильтр /etc/fail2ban/filter.d/postfix-submission.conf:

[Definition]
failregex = ^(?:.+ )?postfix/(?:submission|smtps)/smtpd\[\d+\]: (?:warning|info): .*\[<HOST>\]: SASL (?:\S+ )?authentication (?:failed|failure): .*$

ignoreregex =

Комментарий по регулярке: она не пытается парсить таймстампы и хостнеймы (форматы отличаются между journald и rsyslog), а жёстко привязана к идентификаторам процессов Postfix для клиентских портов и к тексту про ошибку SASL. Токен <HOST> обязателен — так fail2ban извлекает IP.

Создайте jail /etc/fail2ban/jail.d/mail.conf с секцией для Postfix:

[DEFAULT]
banaction = nftables-multiport
banaction_allports = nftables-allports
backend = systemd

[postfix-submission]
enabled = true
filter = postfix-submission
journalmatch = _SYSTEMD_UNIT=postfix.service + SYSLOG_IDENTIFIER=postfix/submission/smtpd
journalmatch = _SYSTEMD_UNIT=postfix.service + SYSLOG_IDENTIFIER=postfix/smtps/smtpd
port = 587,465,submission,smtps
findtime = 15m
maxretry = 5
bantime = 1h
bantime.increment = true
bantime.factor = 2
bantime.maxtime = 12h
ignoreip = 127.0.0.0/8 ::1

Мы используем два journalmatch, чтобы ловить и submission (587), и smtps (465). На системах без journald замените backend на auto или polling и укажите logpath:

[postfix-submission]
backend = auto
logpath = /var/log/mail.log

В этом случае фильтр остаётся тем же, так как он проверяет наличие postfix/(submission|smtps)/smtpd прямо в тексте строки.

Точный jail для Dovecot: только провалы логина

Для Dovecot избегаем всего, что не связано с аутентификацией. Типичные нужные сообщения: Disconnected (auth failed), Aborted login (auth failed), Failed login. Сделаем фильтр /etc/fail2ban/filter.d/dovecot-auth.conf:

[Definition]
failregex = ^(?:.+ )?dovecot: (?:imap|pop3)-login: (?:Aborted login|Disconnected \(auth failed.*\)|Failed login).*rip=<HOST>.*$

ignoreregex = ^(?:.+ )?dovecot: (?:imap|pop3)-login: (?:Disconnected|Logged out).*$

И соответствующий jail:

[dovecot-auth]
enabled = true
filter = dovecot-auth
backend = systemd
journalmatch = _SYSTEMD_UNIT=dovecot.service
port = imap,imaps,pop3,pop3s,143,993,110,995
findtime = 15m
maxretry = 7
bantime = 1h
bantime.increment = true
bantime.factor = 2
bantime.maxtime = 12h

Здесь maxretry можно сделать выше, чем у submission: мобильные клиенты чаще «мазают» паролем после смены или кэшированных автонастроек.

Recidive: бан на сутки для настойчивых

Даже с мягкими порогами полезно иметь «повторник»: если IP несколько раз попадал под бан за последние сутки — выносим длительный приговор, причём по всем портам. Это снижает шум и рескейлинг атак.

[recidive-mail]
enabled = true
filter = recidive
logpath = /var/log/fail2ban.log
findtime = 1d
maxretry = 5
bantime = 24h
banaction = nftables-allports

Этот jail не зависит от отдельных сервисов: он анализирует сам лог fail2ban.

Тестирование фильтров и отладка

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

fail2ban-regex /var/log/mail.log /etc/fail2ban/filter.d/postfix-submission.conf
fail2ban-regex /var/log/mail.log /etc/fail2ban/filter.d/dovecot-auth.conf

Для journald удобно сделать выгрузку примеров:

journalctl -u postfix -n 200 | tee /tmp/postfix.log
journalctl -u dovecot -n 200 | tee /tmp/dovecot.log
fail2ban-regex /tmp/postfix.log /etc/fail2ban/filter.d/postfix-submission.conf
fail2ban-regex /tmp/dovecot.log /etc/fail2ban/filter.d/dovecot-auth.conf

После включения jails:

systemctl reload fail2ban
fail2ban-client status
fail2ban-client status postfix-submission
fail2ban-client status dovecot-auth

Разовый добан/разбан для диагностики:

fail2ban-client set postfix-submission banip 203.0.113.10
fail2ban-client set dovecot-auth unbanip 203.0.113.10

Проверка фильтров fail2ban-regex на почтовых логах

Пороговые значения без ложнопозитивов

Рекомендуемые стартовые настройки:

  • findtime = 15m, maxretry = 5 для submission/SMTPS, maxretry = 7 для Dovecot.
  • bantime = 1h с bantime.increment = true, bantime.factor = 2, bantime.maxtime = 12h.
  • ignoreip для локалхоста, VPN-админок и мониторингов.

Если среди пользователей есть абоненты за общим NAT (провайдеры, офисы), поднимите maxretry на Dovecot, иначе можно случайно банить целые офисные подсети.

Чего не должно быть в фильтрах для почты

Чтобы не банить внешние MX и нормальные почтовые диалоги, избегайте таких признаков:

  • Любые NOQUEUE: reject без явной привязки к SASL-логину — это нормальная антиспамная работа вашего MTA.
  • lost connection, timeout и другие сетевые особенности — у клиентов бывает плохой сигнал или TCP сбои.
  • Срабатывания на одноразовые TLS/SMTP ошибки, не связанные с авторизацией.

Простое правило: баним только за повторные провалы аутентификации пользователя, а не за «плохие письма».

IPv6 и выбор banaction

Если у вас включён IPv6, используйте nftables-действия (nftables-multiport/nftables-allports) — они одинаково хорошо работают для IPv4 и IPv6. Для старых систем с iptables проверьте, что выбранный banaction поддерживает оба стека либо добавьте отдельное действие для v6.

Жизненный цикл: уведомления и отчётность

Для оперативного контроля можно включить email-уведомления в действиях fail2ban. Но помните, что на почтовом сервере важно не захламлять себя письмами о каждом бане. Разумнее уведомлять только о recidive или о количестве заблокированных за период в мониторинге.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Производительность и стабильность

Несколько практик для серверов с высокой нагрузкой:

  • backend = systemd: меньше I/O, проще фильтрация по источнику.
  • Не используйте чрезмерно тяжёлые регулярки с жадными квантификаторами на всю строку — ограничивайте контекст.
  • Не делайте десятки перекрывающихся jails для одного и того же события — лучше один точный.

Для общей жёсткости периметра посмотрите базовую памятку по защите хоста и файрвола: безопасность VDS: SSH и firewall.

Типичные события в логах (для самопроверки)

Postfix (submission/SMTPS):

Jul 20 10:15:22 mx1 postfix/submission/smtpd[1234]: warning: unknown[198.51.100.20]: SASL LOGIN authentication failed: authentication failure
Jul 20 10:15:26 mx1 postfix/smtps/smtpd[1235]: warning: client.example[198.51.100.21]: SASL PLAIN authentication failed: UGFzc3dvcmQ6

Dovecot:

Jul 20 10:16:03 mx1 dovecot: imap-login: Disconnected (auth failed, 3 attempts): user=<user@example.com>, method=PLAIN, rip=203.0.113.4, lip=192.0.2.10, TLS
Jul 20 10:16:10 mx1 dovecot: pop3-login: Aborted login (auth failed, 2 attempts): user=<>, rip=203.0.113.5, lip=192.0.2.10

Если ваши строки заметно отличаются (кастомный формат логов), подправьте регулярные выражения точечно: обычно достаточно изменить часть между префиксом сервиса и полем rip=<HOST> или хвост после SASL ... failed. Для бесшовных переносов ящиков пригодится материал: миграция IMAP без простоя через imapsync.

Экстренные ситуации

Если легитимный клиент попал под бан:

  • Разбаньте IP: fail2ban-client set dovecot-auth unbanip 203.0.113.10.
  • Добавьте в ignoreip, если это постоянный «шумный» адрес мониторинга/шлюза.
  • Проверьте, нет ли опечатки в логине у пользователя или устаревшего пароля в одном из его устройств.

Итог

Точные jails для почты — это прежде всего дисциплина: ловим только повторные провалы авторизации и жёстко ограничиваем источники логов. Postfix — нацеливаемся на submission/SMTPS, Dovecot — только на IMAP/POP3-логины. Добавляем «повторник» на сутки и не забываем тестировать фильтры на реальных логах. Такая схема надёжно останавливает bruteforce и почти не создаёт ложных блокировок, сохраняя доставляемость почты и спокойствие админа.

Поделиться статьей

Вам будет интересно

DMARC: rua, p=quarantine и p=reject — как включить без потери доставляемости OpenAI Статья написана AI (GPT 5)

DMARC: rua, p=quarantine и p=reject — как включить без потери доставляемости

Пошаговое руководство для админов: что такое DMARC и агрегированные отчёты rua, как правильно оформить rua=mailto, собрать XML-отч ...
Floating IP для Nginx: keepalived VRRP, healthcheck и быстрый failover OpenAI Статья написана AI (GPT 5)

Floating IP для Nginx: keepalived VRRP, healthcheck и быстрый failover

Пошагово строим отказоустойчивый фронтенд на двух серверах Nginx с общим floating IP. Настраиваем keepalived (VRRP), HTTP health c ...
SYNPROXY в nftables: защита VDS от TCP SYN flood пошагово OpenAI Статья написана AI (GPT 5)

SYNPROXY в nftables: защита VDS от TCP SYN flood пошагово

SYN flood забивает TCP-очереди и conntrack на VDS, съедая CPU. SYNPROXY в nftables отсекает мусор до TCP-стека. Разбираем принцип, ...