psj-notes
~/home ~/series ~/archive

Часть 05. sslh и Fail2ban — швейцарский нож и сторожевой пёс

01.01.1970 Серия: Руководство по настройке srv02-Helsinki 'sslh' 'fail2ban' 'безопасность'

Часть 05. sslh и Fail2ban — швейцарский нож и сторожевой пёс

«Одного замка на двери мало. Мало даже двух. Злоумышленник должен пройти через три двери, пока поймёт, что за первой — ничего нет.» — Воланд


Глава 1. Что такое sslh

sslh (SSL/SSH multiplexer) — это демон, который слушает один порт (обычно 80), смотрит на тип входящего трафика и направляет его в нужное место.

Как это работает:

  • Подключаетесь по SSH на порт 80 → sslh видит SSH-рукопожатие → перенаправляет на 127.0.0.1:22022
  • Браузер запрашивает HTTP на порт 80 → sslh видит HTTP-заголовок → перенаправляет на 127.0.0.1:8080 (будущий Nginx)

Зачем это нужно. Порт 80 (HTTP) открыт всегда — любой сайт должен быть доступен. Если вы идёте по SSH через порт 80, это выглядит как обычный веб-трафик. Порт 22022 при этом остаётся прямым входом для админа, а порт 80 — запасным.

Бегемот, настраивая монокль:
«Представьте парадный вход в дом. Швейцар смотрит на гостя: если с ноутбуком и в тапочках — отправляет в библиотеку. Если в бабочке и с коньяком — в гостиную. Одна дверь, два назначения. Элегантно.»


Глава 2. Установка sslh

sslh есть в стандартных репозиториях Ubuntu:

sudo apt update && sudo apt install -y sslh

Ожидаемый вывод (в конце):

Setting up sslh (2.0.1-1) ...

Проверяем версию:

sslh -V

Ожидаемый вывод:

sslh 2.0.1

Глава 3. Настройка sslh

Конфигурационный файл sslh находится в /etc/default/sslh. Редактируем его:

sudo nano /etc/default/sslh

Приводим содержимое к следующему виду:

# Default options for sslh initscript
# sourced by /etc/init.d/sslh

# binary to use: forked (sslh) or single-thread (sslh-select) version
# systemd users: don't forget to modify /lib/systemd/system/sslh.service
DAEMON=/usr/sbin/sslh

DAEMON_OPTS="--user sslh --listen 0.0.0.0:80 --ssh 127.0.0.1:22022 --http 127.0.0.1:8080"

Пояснение параметров:

  • DAEMON=/usr/sbin/sslh — используем forked-версию (создаёт отдельный процесс на каждое соединение)
  • --user sslh — демон работает от имени одноимённого системного пользователя
  • --listen 0.0.0.0:80 — слушаем порт 80 на всех интерфейсах
  • --ssh 127.0.0.1:22022 — SSH-трафик направляем на локальный SSH-сервер
  • --http 127.0.0.1:8080 — HTTP-трафик направляем на будущий Nginx (пока не установлен — соединения будут отклоняться, это нормально)

Перезапускаем сервис и добавляем в автозагрузку:

sudo systemctl restart sslh && sudo systemctl enable sslh

Ожидаемый вывод:

Synchronizing state of sslh.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install enable sslh

Проверяем, что sslh слушает порт 80:

sudo ss -tlnp | grep 80

Ожидаемый вывод:

LISTEN 0      10          0.0.0.0:80        0.0.0.0:*    users:(("sslh-select",pid=1234,fd=3))
LISTEN 0      10             [::]:80           [::]:*    users:(("sslh-select",pid=1234,fd=4))

Глава 4. Проверка sslh на клиенте

На вашем локальном компьютере (не на сервере!) добавляем в ~/.ssh/config второй хост для подключения через порт 80:

# Подключение к srv02-Helsinki
Host srv02
    HostName XX.XX.XX.XX
    Port 22022
    User user01
    IdentityFile ~/.ssh/id_ed25519_srv02

# Подключение через sslh (порт 80)
Host srv02-web
    HostName XX.XX.XX.XX
    Port 80
    User user01
    IdentityFile ~/.ssh/id_ed25519_srv02

Проверяем подключение через sslh:

ssh srv02-web

Если подключение успешно — sslh работает. Выходим (exit) и продолжаем использовать штатный хост srv02 (порт 22022) для повседневной работы.

Коровьев, разглядывая лог:
«Вошли через парадную дверь. Швейцар узнал своего, пропустил без очереди. А со стороны — обычный пакет на 80-й порт. Поди разбери, кто там: админ или браузер.»


Глава 5. Что такое Fail2ban

Fail2ban — это демон, который следит за логами сервисов (SSH, Nginx, и т.д.) и блокирует IP-адреса, с которых приходит слишком много неудачных попыток подключения.

Блокировка происходит на уровне фаервола — UFW получает правило deny для заблокированного IP. Через 30 минут блокировка снимается автоматически.

Типичная атака на SSH: бот перебирает пароли со скоростью 3-5 попыток в секунду. Fail2ban засекает 5 неудачных попыток за 10 минут — и IP уходит в бан.

Бегемот, потягиваясь:
«Сторожевой пёс не лает на каждую проходящую кошку. Но если кто-то слишком долго скребётся в замочную скважину — пёс встаёт и кладёт лапу на дверь.»


Глава 6. Установка Fail2ban

sudo apt install -y fail2ban

Ожидаемый вывод (в конце):

Setting up fail2ban (1.0.2-2) ...

Проверяем версию:

fail2ban-server --version

Ожидаемый вывод:

Fail2Ban v1.0.2

Глава 7. Настройка Fail2ban для SSH

Fail2ban использует два типа файлов конфигурации:

  • /etc/fail2ban/jail.conf — стандартный, не редактируется (перезаписывается при обновлении)
  • /etc/fail2ban/jail.local — ваш файл с собственными настройками (имеет приоритет)

Создаём jail.local:

sudo nano /etc/fail2ban/jail.local

Содержимое:

[sshd]
enabled = true
port = 22022
logpath = %(sshd_log)s
maxretry = 3
bantime = 86400
findtime = 600

Пояснение параметров:

  • enabled = true — включаем тюрьму для SSH
  • port = 22022 — нестандартный порт SSH; Fail2ban передаёт его в правило UFW, чтобы блокировать атакующий IP только на этом порту
  • logpath = %(sshd_log)s — ссылка на переменную из jail.conf, где прописан /var/log/auth.log
  • maxretry = 3 — три неудачные попытки → бан
  • bantime = 86400 — время блокировки: 86 400 секунд = 24 часа. Сутки — вполне разумный срок: бот уходит к другой жертве и уже не возвращается
  • findtime = 600 — окно подсчёта попыток: 600 секунд = 10 минут

Перезапускаем Fail2ban:

sudo systemctl restart fail2ban && sudo systemctl enable fail2ban

Ожидаемый вывод:

Synchronizing state of fail2ban.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install enable fail2ban

Глава 8. Проверка работы Fail2ban

Проверяем статус SSH-защиты:

sudo fail2ban-client status sshd

Ожидаемый вывод:

Status for the jail: sshd
|- Filter
|  |- Currently failed:	0
|  |- Total failed:	0
|  `- File list:	/var/log/auth.log
`- Actions
   |- Currently banned:	0
   |- Total banned:	0
   `- Banned IP list:

Пока никто не забанен — сервер новый. Через пару дней список Total banned покажет, сколько ботов пыталось пробиться.

Проверяем, что Fail2ban видит логи SSH:

sudo tail -5 /var/log/fail2ban.log

Ожидаемый вывод (пример):

2026-07-26 18:00:00,123 fail2ban.server         [1234]: INFO    Ready for action
2026-07-26 18:00:01,456 fail2ban.filter         [1234]: INFO    Added logfile: /var/log/auth.log (pos = 12345, hash = abcdef...)
2026-07-26 18:00:01,789 fail2ban.jail           [1234]: INFO    Jail 'sshd' started

Если строка Jail 'sshd' started есть — всё работает.

Воланд, перебирая забаненные IP:
«Три неудачных попытки за десять минут — и гости с таким адресом отправляются в сад. На сутки. Бот вернётся завтра, сделает ещё три попытки — и сядет снова. Бесконечный ад для железа.»

Глава 9. Дополнительная тюрьма: админка блога

На сервере уже настроена вторая тюрьма — для защиты панели управления блогом:

sudo nano /etc/fail2ban/jail.local

Дописываем в конец файла:

[psj-admin-login]
enabled = true
port = http,https
logpath = /var/log/nginx/access.log
maxretry = 3
bantime = 86400
findtime = 300

Пояснение:

  • port = http,https — блокировка на портах 80 и 443; какой именно порт — неважно, атакующий IP будет заблокирован на обоих
  • logpath = /var/log/nginx/access.log — Fail2ban будет сканировать лог Nginx на предмет неудачных попыток входа в админку
  • findtime = 300 — окно подсчёта: 5 минут

Эта тюрьма заработает в полную силу после установки Nginx и движка блога. Fail2ban уже настроен и ждёт.

Перезапускаем Fail2ban, чтобы применить изменения:

sudo systemctl restart fail2ban

Глава 10. Обновление UFW (ещё раз)

Порт 80 у нас уже открыт (добавлен в части 04). Проверяем актуальные правила:

sudo ufw status verbose

Ожидаемый вывод:

Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing)
New profiles: skip

To                         Action      From
--                         ------      ----
22022/tcp                  LIMIT       Anywhere
80/tcp                     ALLOW       Anywhere
443/tcp                    ALLOW       Anywhere
22022/tcp (v6)             LIMIT       Anywhere (v6)
80/tcp (v6)                ALLOW       Anywhere (v6)
443/tcp (v6)               ALLOW       Anywhere (v6)

Порт 80 открыт — sslh может работать. Порт 443 пока не используется (откроемся позже, когда поставим Nginx с SSL).


Финал части: Резюме Воланда

Параметр Статус
sslh установлен и слушает порт 80
SSH доступен через порт 80 (sslh)
SSH доступен через прямой порт 22022
HTTP-трафик перенаправляется на 8080
Fail2ban установлен
Защита SSH: 3 попытки за 10 мин → бан на сутки
Защита админки блога (psj-admin-login)
UFW: порты 80, 443, 22022 открыты

Воланд подводит итог пятой части:
«Парадная дверь прикрыта sslh — швейцар разбирает гостей. Чёрный ход (22022) стережёт Fail2ban — три попытки, и на сутки в сад. Админка блога пока спит — пёс уже поставлен на пост. Пора ставить веб-сервер!»

Комментарии

Комментарии пока не подключены.