SSH — одна из самых атакуемых точек входа на сервер. В типичном сценарии ботнет гонит тысячи попыток логина (brute force), а вы видите рост нагрузки CPU, всплеск контекстных переключений, очереди на принятие соединений и огромный поток записей в логах. Иногда это похоже на DDoS: цель не «угадать пароль», а занять ресурсы и лишить вас доступа.
Хорошая новость: OpenSSH умеет довольно эффективно «срезать» лишние подключения на ранней стадии. Ниже — практический набор настроек MaxStartups, LoginGraceTime, а также варианты rate limit на уровне файрвола. Плюс — как подтвердить проблему через journalctl и не заблокировать собственные админские доступы.
Как атаки на SSH превращаются в нагрузку
Основная нагрузка возникает не столько от «проверки пароля», сколько от множества конкурентных соединений и криптографии при установлении сеанса (обмен ключами, шифрование). Даже при неуспешной аутентификации серверу нужно принять TCP-соединение, выполнить рукопожатие, подождать ввод, записать логи.
Ключевой момент: до успешной аутентификации соединение считается неавторизованным и может «висеть» довольно долго. Если таких соединений много, sshd начинает тратить ресурсы на обслуживание очередей и таймеров, а легитимные подключения начинают ждать или отваливаться.
Задача антифлуда для SSH — ограничить число неавторизованных сессий и время, которое
sshdготов их терпеть, не ломая нормальные интерактивные входы и автоматизацию.
Быстрая диагностика: убедиться, что виноват именно SSH
Проверить всплеск событий в journald
На системах с systemd обычно достаточно journald. Сначала оцените объём и характер событий:
sudo journalctl -u sshd --since "1 hour ago" --no-pager
sudo journalctl -u sshd --since "10 min ago" --no-pager | tail -n 200
Ищите повторяющиеся паттерны: Failed password, Invalid user, Connection closed, Too many authentication failures, maximum authentication attempts exceeded, а также частоту событий в секунду.
Свести статистику по IP и пользователям
Простейшая агрегация по источникам (для первичной оценки):
sudo journalctl -u sshd --since "1 hour ago" --no-pager | grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}' | sort | uniq -c | sort -nr | head
sudo journalctl -u sshd --since "1 hour ago" --no-pager | grep -E "Failed password|Invalid user" | head
Если видите десятки-сотни IP с небольшой частотой — это «широкий» брут. Если 1–3 IP долбят очень плотно — это похоже на точечный флуд, который удобно душить лимитами на уровне файрвола.
Проверить количество текущих соединений
ss -tn state established '( sport = :22 )' | wc -l
ss -tn state syn-recv '( sport = :22 )' | wc -l
ss -tnp '( sport = :22 )' | head
Много SYN-RECV может указывать на сетевой флуд или проблему с backlog/файрволом. Много ESTAB от неожиданных адресов — на «медленные» подключения, которые держатся до аутентификации.
Если сервер регулярно ловит такие атаки, проще жить на отдельном VDS: там легче изолировать нагрузку, настроить файрвол и не делить ресурсы с соседями.
MaxStartups: главный рычаг против неавторизованных соединений
MaxStartups ограничивает количество «незавершённых» (до успешной аутентификации) входов. Это именно тот слой, который чаще всего забивают боты.
Формат значения может быть простым числом или тройкой start:rate:full:
start— после какого количества неавторизованных соединений включается «случайный отстрел» новых подключений;rate— вероятность отбрасывания (в процентах) на этапе междуstartиfull;full— жёсткий предел, после которого новые подключения будут отвергаться всегда.
Практичные значения для небольших серверов
Универсального значения нет: зависит от того, как вы используете SSH (одиночные входы, CI/CD, bastion, много админов) и от мощности CPU.
Для большинства небольших серверов обычно хватает умеренного ограничения, например:
MaxStartups 10:30:60
Что это даёт: до 10 неавторизованных соединений всё идёт нормально; дальше sshd начинает постепенно отбрасывать новые подключения; при 60 — режет жёстко. Это заметно снижает эффект «занятия слотов» ботами.
Где менять и как безопасно применить
Настройка находится в /etc/ssh/sshd_config или в /etc/ssh/sshd_config.d/*.conf (зависит от дистрибутива). На практике удобнее добавлять отдельным файлом в sshd_config.d, чтобы не терять правки при обновлениях пакетов.
sudo sshd -t
sudo systemctl reload sshd
Используйте reload, а не restart, чтобы не оборвать активные сессии. Перед применением всегда проверяйте конфиг командой sshd -t.

LoginGraceTime: уменьшить время «подвисших» логинов
LoginGraceTime задаёт, сколько времени sshd ждёт, пока пользователь успешно пройдёт аутентификацию. При атаке это время превращается в «держатель ресурсов»: бот может открывать соединения и тянуть время.
На многих системах значение по умолчанию порядка минуты-двух. Для серверов, где администраторы заходят по ключам, обычно безопасно снижать.
Рекомендации по значению
- Если вход по ключам и интерактив почти не нужен:
LoginGraceTime 20sили30s. - Если бывают входы с паролем/2FA и возможны задержки:
LoginGraceTime 45s–60s.
Пример:
LoginGraceTime 30s
Слишком агрессивное снижение может мешать легитимным пользователям при высоких задержках сети или если включены дополнительные проверки PAM, которые иногда «думают». После изменения протестируйте вход из вашей «худшей» точки (например, через мобильный интернет или VPN).
Rate limit SSH: где правильнее ограничивать частоту
Ограничивать частоту подключений можно на нескольких уровнях. Идея простая: не давать одному источнику создавать слишком много новых соединений за короткое время. Это полезно и против brute force, и против флуд-атак на handshake.
Уровень 1: на стороне sshd (ограничение слотов)
MaxStartups — это «лимитер по параллельности». Он не считает «запросы в секунду», но хорошо ограничивает эффект от массовых полу-логинов.
Плюсы: не требует файрвола и работает даже при сложных сетевых правилах. Минусы: атака всё равно доходит до sshd и потребляет часть CPU на приём и обработку соединений.
Уровень 2: nftables (отсечь раньше и дешевле)
Лимитирование на файрволе часто эффективнее по CPU: пакеты отбрасываются до того, как приложение начнёт работу. Ниже — пример для nftables. Важно: это демонстрация принципа, адаптируйте под свою схему, чтобы не поломать доступ.
sudo nft add table inet filter
sudo nft add chain inet filter input '{ type filter hook input priority 0; policy accept; }'
sudo nft add rule inet filter input tcp dport 22 ct state new limit rate 15/minute burst 20 accept
sudo nft add rule inet filter input tcp dport 22 ct state new drop
Логика: разрешаем ограниченное число новых соединений в минуту с небольшим burst, остальное — дроп. Если у вас CI/CD создаёт много новых SSH-сессий (без multiplexing), лимит придётся поднять или сделать исключения по IP.
Уровень 3: дополнительные инструменты (по ситуации)
Иногда помогает fail2ban или аналоги (банят IP по логам), а также перенос SSH за bastion/Jump Host. Но если цель — быстро «сбить» нагрузку, в большинстве случаев проще и надёжнее сочетание MaxStartups + аккуратный лимит на файрволе.
Hardening SSH: уменьшить поверхность атаки
Лимиты — это реакция на симптом. Hardening уменьшает вероятность успешной атаки и снижает нагрузку от бесполезных попыток аутентификации.
Отключить пароли там, где это возможно
Если вы администрируете сервер по ключам, отключение паролей резко снижает смысл brute force:
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
Если используются PAM-модули для 2FA, отключайте интерактивную аутентификацию только если уверены, что это не сломает вашу схему входа.
Ограничить доступ по пользователям
Простой способ уменьшить шум — разрешить вход только конкретным пользователям:
AllowUsers admin deploy
Это не «защита от DDoS», но уменьшает объём проверок и логов, а также снижает риск ошибки с лишними аккаунтами.
Понизить число попыток аутентификации
MaxAuthTries уменьшает количество попыток в рамках одного соединения и экономит ресурсы:
MaxAuthTries 3
Ограничить форвардинги и лишние возможности
Если SSH используется только как админский доступ, часто разумно отключить то, чем вы не пользуетесь:
AllowTcpForwarding no
X11Forwarding no
PermitTunnel no
Если SSH используется для администрирования веб-проектов, не забывайте закрывать фронт правильными SSL-сертификатами и нормальной политикой доступа: это не заменяет SSH-hardening, но заметно снижает общий риск компрометации.

Проверка изменений: стало ли легче CPU и доступнее SSH
Тест: не отрезали ли вы себя
- Держите открытую текущую SSH-сессию как «страховку».
- Откройте вторую сессию с нового терминала и проверьте логин.
- Проверьте вход с той же подсети, где обычно работаете (VPN/офис/дом).
- Убедитесь, что автоматизация (deploy/backup/monitoring) не упирается в лимиты.
Сравнить логи до/после
sudo journalctl -u sshd --since "10 min ago" --no-pager | tail -n 200
После настройки MaxStartups и/или файрвол-лимита вы чаще будете видеть ранние отказы при подключении (и, главное, меньше общей нагрузки на систему).
Оценить текущую ситуацию по сокетам
ss -s
ss -tn state syn-recv '( sport = :22 )' | head
При удачной настройке число «подвисших» состояний и общая турбулентность по TCP должны снизиться.
Типичные ошибки и как их избежать
Слишком жёсткий MaxStartups
Если поставить, например, MaxStartups 3 на сервер, где параллельно работает несколько админов и CI, вы получите «само-DDoS» при любом всплеске. Начинайте с умеренных значений и повышайте строгость постепенно.
Слишком маленький LoginGraceTime
LoginGraceTime 5s допустим только в очень контролируемой среде. Для реальной жизни (особенно с PAM/2FA) это риск ложных отказов.
Rate limit на файрволе без исключений
Если вы администрируете сервер через один NAT-адрес (офис/VPN), то при одновременных входах нескольких людей лимит легко сработает против вас. В таких случаях добавляют исключения для доверенных подсетей или повышают burst.
Мини-чеклист «анти-SSH-флуд»
- Подтвердите симптоматику:
journalctl -u sshd, количествоSYN-RECV, частоту событий. - Настройте
MaxStartupsв форматеstart:rate:full(например,10:30:60). - Уменьшите
LoginGraceTimeдо разумного (часто30s). - Добавьте rate limit на файрволе, если атака плотная и грузит CPU.
- Сделайте базовый hardening: ключи вместо паролей, ограничение пользователей,
MaxAuthTries. - Проверьте, что легитимные входы и автоматизация не ломаются.
Итог
Комбинация MaxStartups + адекватный LoginGraceTime закрывает самый частый сценарий перегруза SSH от массы неавторизованных подключений. Если атака плотная, добавляйте ограничение частоты на уровне файрвола: это дешевле по ресурсам и быстрее «гасит» поток. А дальше уже hardening: чем меньше вариантов аутентификации и «лишних» пользователей, тем меньше поверхность атаки и меньше шума в логах.
Если после внедрения лимитов вы всё ещё видите устойчивый рост CPU именно на sshd, отдельно проверьте задержки DNS/GSSAPI, сетевую картину (SYN flood, conntrack), а также лимиты файловых дескрипторов. Но в большинстве практических случаев описанных шагов достаточно, чтобы вернуть управляемость и стабильный доступ по SSH.


