MAATRIX GAMES / Блог / fail2ban для защиты SSH игрового сервера

fail2ban для защиты SSH игрового сервера

MAATRIX GAMES

Если у вашего VPS есть публичный IP и открытый 22 порт, боты найдут его за считаные часы — и начнут долбить SSH тысячами попыток подбора пароля в сутки. Для игрового сервера это не абстрактная угроза: получив доступ по SSH, атакующий доберётся до RCON-паролей, конфигов и бэкапов мира, а заодно может превратить вашу машину в узел ботнета. fail2ban не остановит целенаправленную атаку, но перебор паролей — самый частый и самый дешёвый вектор — он режет практически под корень. Разберём установку, рабочий jail для sshd и то, как потом разбанить самого себя, когда вы случайно словите бан со своего же IP.

Что делает fail2ban и почему этого достаточно для старта

fail2ban — это демон, который читает логи (в нашем случае /var/log/auth.log на Debian/Ubuntu или /var/log/secure на CentOS/AlmaLinux) и ищет в них паттерны неудачных попыток входа. Как только с одного IP набирается заданное число фейлов за заданное время — fail2ban добавляет временное правило в firewall (iptables, nftables или ufw, в зависимости от бэкенда) и блокирует этот адрес целиком, не только для SSH.

Это не замена нормальной гигиене: отключённому паролевому входу с SSH-ключами, смене порта 22 на нестандартный, VPN для админского доступа. Но fail2ban закрывает конкретную дыру — автоматический перебор — и делает это без вашего участия, в фоне, бесплатно. Для соло-админа, который поднял VPS под Minecraft, Rust или CS2 и не горит желанием разворачивать полноценный SIEM, это разумный баланс усилий и результата. Если у вас уже есть VPN для администраторов и SSH закрыт для всех кроме VPN-подсети — fail2ban всё равно не помешает как второй рубеж, мало ли VPN отвалится или порт временно откроется для гостевого доступа.

Установка на VPS

На Ubuntu/Debian:

sudo apt update
sudo apt install fail2ban -y
sudo systemctl enable --now fail2ban
sudo systemctl status fail2ban

На CentOS Stream / AlmaLinux / Rocky Linux пакет лежит в EPEL:

sudo dnf install epel-release -y
sudo dnf install fail2ban -y
sudo systemctl enable --now fail2ban

Проверьте, что сервис реально запущен и слушает бэкенд firewall:

sudo fail2ban-client status

Если команда вернула список jail (пока, скорее всего, пустой или с одним sshd по умолчанию) — демон жив. На части дистрибутивов после установки sshd-jail уже включён из коробки в /etc/fail2ban/jail.conf, но трогать этот файл не стоит — он перезатирается при обновлении пакета. Вся ваша конфигурация идёт в отдельный файл, который fail2ban подхватывает поверх.

Нужен игровой сервер?

MAATRIX GAMES — 45+ игр, деплой за минуты, DDoS-защита, автобэкапы. Тарифы от 399 ₽/мес.

Создать сервер

Базовый jail для SSH

Создайте /etc/fail2ban/jail.local — именно .local, не .conf:

sudo nano /etc/fail2ban/jail.local

Минимальная рабочая конфигурация:

[DEFAULT]
# свой IP и подсети, которые никогда не банить
ignoreip = 127.0.0.1/8 ::1 203.0.113.45

# сколько попыток допустимо
maxretry = 5

# окно, за которое считаются попытки (10 минут)
findtime = 10m

# на сколько банить
bantime = 1h

# бэкенд чтения логов (systemd на большинстве современных дистрибутивов)
backend = systemd

[sshd]
enabled = true
port = ssh
filter = sshd
maxretry = 4
findtime = 10m
bantime = 1h

Замените 203.0.113.45 на свой реальный IP (посмотреть его можно на любом сервисе вроде ifconfig.me) — иначе рискуете забанить самого себя при опечатке в пароле, а восстанавливать доступ придётся через консоль хостера. Если у вас нестандартный SSH-порт (что само по себе хорошая практика — см. настройку портов и файрвола), поменяйте port = ssh на конкретный номер, например port = 2222.

Перезапустите сервис и проверьте, что jail активен:

sudo systemctl restart fail2ban
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 пустая или ошибка про несуществующий лог-файл — значит backend не совпадает с тем, как ваш дистрибутив пишет логи. На системах с systemd почти всегда работает backend = systemd; на старых установках без journald нужен backend = auto и путь logpath = /var/log/auth.log (Debian/Ubuntu) или /var/log/secure (RHEL-семейство) в секции [sshd].

Тонкая настройка: escalation и recidive

Плоский bantime в час — это компромисс, но ботов, которые упорно возвращаются, разумно банить дольше. fail2ban умеет наращивать срок бана с каждым повторным нарушением одного и того же IP:

[DEFAULT]
bantime.increment = true
bantime.factor = 2
bantime.maxtime = 1w
bantime.multipliers = 1 5 30 60 300 720 1440

При включённом bantime.increment каждый следующий бан того же адреса умножается на bantime.factor, пока не упрётся в bantime.maxtime. Это удобнее, чем вручную крутить maxretry.

Второй полезный jail — recidive, который смотрит уже не в лог sshd, а в собственный лог fail2ban (/var/log/fail2ban.log) и банит на длительный срок IP, которые попадали в бан несколько раз за короткий период:

[recidive]
enabled = true
filter = recidive
logpath = /var/log/fail2ban.log
action = %(action_mwl)s
bantime = 1w
findtime = 1d
maxretry = 3

Action %(action_mwl)s (ban + write to log + отправка письма) требует настроенного локального MTA — если почта не настроена, используйте просто %(action_)s, иначе получите ошибки при попытке банить.

Разбан по IP: свой и чужой

Рано или поздно вы забаните сами себя — сменили пароль, ошиблись пару раз, или подключаетесь через новый VPN-выход. Проверить текущий список банов:

sudo fail2ban-client status sshd

Снять бан с конкретного IP:

sudo fail2ban-client set sshd unbanip 203.0.113.45

Если доступа по SSH уже нет вообще (сами себя заблокировали, а альтернативного входа нет), это придётся делать через веб-консоль хостера (VNC/serial console), которая обычно не завязана на SSH-порт и не подпадает под бан iptables:

# зайдя через веб-консоль хостера
sudo fail2ban-client unban --all
# или точечно
sudo fail2ban-client set sshd unbanip <ваш IP>

Разбанить сразу все IP во всех jail:

sudo fail2ban-client unban --all

Добавить IP в постоянный whitelist без перезапуска сервиса (изменения в jail.local требуют restart, а это временно):

sudo fail2ban-client set sshd addignoreip 203.0.113.45

Это действует до перезапуска демона — постоянную запись всё равно нужно продублировать в ignoreip внутри jail.local.

Логи: кто и когда стучался

Все действия fail2ban пишет в /var/log/fail2ban.log. Посмотреть последние баны:

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

Посмотреть, кто уже разбанен:

sudo grep 'Unban ' /var/log/fail2ban.log | tail -n 30

Живой мониторинг банов в реальном времени (удобно оставить в отдельной tmux-панели рядом с консолью игрового сервера — см. systemd, screen и tmux для игровых процессов):

sudo tail -f /var/log/fail2ban.log | grep --line-buffered 'Ban\|Unban'

Если хочется коротких оповещений в Telegram при каждом бане, самый простой вариант — обёртка вокруг logpath: сторонний скрипт слушает fail2ban.log через tail -F и дёргает Telegram Bot API при совпадении строки Ban. Полноценный action с email внутри fail2ban тоже возможен, но требует локального MTA (postfix/exim), что для одиночного VPS часто избыточно — проще внешний watcher-скрипт.

Полезно также раз в неделю смотреть общую статистику по количеству банов — резкий скачок числа уникальных атакующих IP может говорить о том, что ваш IP попал в свежий список для сканирования ботнетов, и стоит на время ужесточить maxretry до 2-3.

Частые грабли

Несколько вещей, на которых спотыкаются чаще всего:

  • Правки в jail.conf вместо jail.local. Файл jail.conf перезаписывается при обновлении пакета — все ваши изменения улетят. Всегда используйте jail.local или файлы в jail.d/.
  • Забыли добавить свой IP в ignoreip. Особенно больно, если у вас динамический IP от домашнего провайдера — он может смениться, и старая запись в whitelist перестанет работать.
  • iptables и ufw конфликтуют. Если на сервере уже настроен ufw (см. настройку портов и файрвола), убедитесь, что action в fail2ban использует правильный бэкенд (action_ufw вместо стандартного iptables-multiport), иначе правила могут не применяться или дублироваться.
  • Docker и NAT ломают видимость реального IP. Если sshd работает внутри контейнера или за проброшенным портом с NAT, в логах может оказаться внутренний адрес вместо реального — тогда бан просто не сработает по назначению. В таких схемах SSH лучше держать на хосте, а не в контейнере.
  • fail2ban не спасает от credential stuffing на панель управления. Это защита конкретно SSH (и опционально других сервисов через дополнительные jail — nginx, панели вроде Pterodactyl). Для веб-панели управления сервером нужна отдельная защита — двухфакторка, о которой ниже.

Нужен игровой сервер?

MAATRIX GAMES — 45+ игр, деплой за минуты, DDoS-защита, автобэкапы. Тарифы от 399 ₽/мес.

Создать сервер

Частые вопросы

Нужен ли fail2ban, если SSH-вход по паролю уже отключён и разрешены только ключи?

Формально перебор пароля тогда бессмыслен, но fail2ban всё равно полезен: он банит IP за сам факт попыток подключения без валидного ключа, снижая шум в логах и нагрузку на sshd от постоянных рукопожатий ботов.

Забанит ли fail2ban легитимного игрока, который просто зашёл на игровой порт сервера (25565, 27015 и т.д.)?

Нет, jail sshd слушает только логи аутентификации SSH-демона и не имеет отношения к игровому трафику на других портах.

Как временно полностью отключить бан, не выключая fail2ban?

Смените action в jail.local на action = %(action_)s без блокирующей части или установите bantime = 1 (секунда) — но проще на время диагностики просто systemctl stop fail2ban, не забыв потом включить обратно.

Стоит ли ставить fail2ban вместе с двухфакторной аутентификацией на панель управления?

Да, это разные уровни защиты одного и того же VPS: fail2ban режет перебор на уровне SSH-порта, а 2FA для панели управления закрывает веб-доступ к самой панели хостинга игрового сервера. Одно не заменяет другое.

Можно ли добавить jail для RCON или других сервисов игрового сервера?

Да, если у сервиса есть текстовый лог с распознаваемым паттерном неудачных попыток, можно написать свой filter в /etc/fail2ban/filter.d/ и завести под него отдельный jail — принцип тот же, что и для sshd.