Защита SSH-сервера в Linux: ключи, ограничения и журналирование
Защита SSH-сервера начинается с входа по ключу и отключения паролей и root в отдельном файле sshd_config.d. Затем доступ ограничивают по группе и сети, включают защиту от перебора и учатся читать журналы. Ниже рабочий конфиг для OpenSSH 10.x в Debian 13, Ubuntu 26.04 и Fedora 44 и способы не потерять доступ при настройке.

Содержание
От чего защищаем SSH и в каком порядке
Открытый в интернет порт 22 начинают перебирать боты через считаные минуты после запуска сервера. Сам OpenSSH надёжен, проблемы почти всегда в настройке: вход по паролю, root с паролем, забытые тестовые учётки. Порядок действий, который не оставит вас за запертой дверью:
- Настроить вход по ключу и убедиться, что он работает.
- Отключить пароли и root через отдельный файл конфигурации.
- Ограничить, кто и откуда может подключаться.
- Включить защиту от перебора и разобраться с журналами.
Всё это проверено на OpenSSH ветки 10.x, которая стоит в Debian 13, Ubuntu 26.04 LTS и Fedora 44. В ней по умолчанию включён постквантовый обмен ключами mlkem768x25519-sha256, полностью удалена поддержка DSA, а код аутентификации вынесен в отдельный процесс sshd-auth. Если у вас ещё старые DSA-ключи, сервер их просто не примет. Посмотреть версию клиента можно командой ssh -V.
Вход по ключу вместо пароля
Ключ создаётся на вашем компьютере, а не на сервере. Алгоритм Ed25519 короткий, быстрый и поддерживается везде:
ssh-keygen -t ed25519 -a 100 -C "anna@laptop"
ssh-copy-id -i ~/.ssh/id_ed25519.pub anna@server.example
ssh -i ~/.ssh/id_ed25519 anna@server.example
Параметр -a 100 увеличивает число раундов шифрования закрытого ключа, поэтому украденный файл ключа сложнее расшифровать перебором парольной фразы. Парольную фразу ставьте обязательно, а чтобы не вводить её каждый раз, используйте ssh-agent или связку ключей рабочего стола.
Если есть аппаратный ключ с FIDO2 (YubiKey, SoloKey, Nitrokey), можно сделать ключ, который без физического касания устройства не работает:
ssh-keygen -t ed25519-sk -C "anna-fido"
Подробно про клиентскую часть, файл ~/.ssh/config и проброс портов написано в статье как подключиться по SSH. Дальше считаем, что вход по ключу у вас уже проверен в отдельном окне терминала.
Конфигурация sshd через отдельный файл
Основной /etc/ssh/sshd_config лучше не трогать: при обновлении пакета менеджер начнёт спрашивать, чью версию оставить. В Debian, Ubuntu и Fedora в начале этого файла есть строка Include /etc/ssh/sshd_config.d/*.conf, проверьте её и в своём дистрибутиве. Создайте файл /etc/ssh/sshd_config.d/10-hardening.conf:
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
AuthenticationMethods publickey
MaxAuthTries 3
LoginGraceTime 30
AllowGroups sshusers
X11Forwarding no
AllowAgentForwarding no
ClientAliveInterval 300
ClientAliveCountMax 2
LogLevel VERBOSE
Важная деталь: в sshd побеждает первое найденное значение параметра, а не последнее. Файлы из каталога читаются по алфавиту, поэтому номер 10 в имени ставит наш файл раньше, например, 50-cloud-init.conf, который на облачных образах Ubuntu часто включает вход по паролю.
| Параметр | Значение | Зачем |
|---|---|---|
| PermitRootLogin | no или prohibit-password | Root не входит напрямую или входит только по ключу |
| PasswordAuthentication | no | Пароли нельзя перебрать, если их не принимают |
| KbdInteractiveAuthentication | no | Закрывает обходной путь ввода пароля через PAM |
| AllowGroups / AllowUsers | sshusers | Входят только явно разрешённые |
| MaxAuthTries | 3 | Меньше попыток за одно соединение |
| LoginGraceTime | 30 | Незавершённый вход обрывается через 30 секунд |
| AllowAgentForwarding, X11Forwarding | no | Отключает то, чем вы не пользуетесь |
| LogLevel | VERBOSE | Больше деталей в журнале, включая отпечатки отвергнутых ключей |
Создайте группу и добавьте в неё себя до перезапуска, иначе AllowGroups закроет вход и вам:
sudo groupadd sshusers
sudo usermod -aG sshusers anna
# проверка синтаксиса
sudo sshd -t
# какие значения реально применятся
sudo sshd -T | grep -Ei 'passwordauth|permitroot|allowgroups'
# применить: Debian, Ubuntu
sudo systemctl reload ssh
# применить: Fedora, Arch
sudo systemctl reload sshd
Не закрывайте текущую SSH-сессию, пока не проверите вход в новом окне. Уже открытое соединение переживает reload, и через него можно исправить ошибку. На VPS заранее найдите в панели хостинга веб-консоль: это последний способ попасть на сервер, если ключ не пускает.
Смена порта, сокет-активация Ubuntu и SELinux
Нестандартный порт не делает сервер безопаснее, зато резко уменьшает шум в журналах от массовых сканеров. Если решили менять, учтите особенности дистрибутивов.
Ubuntu
С Ubuntu 22.10 ssh запускается через сокет systemd. Порт по-прежнему задаётся директивой Port: генератор systemd читает sshd_config и файлы из sshd_config.d и по ним собирает ssh.socket. Поэтому после правки нужно перечитать юниты и перезапустить сокет:
echo "Port 2222" | sudo tee /etc/ssh/sshd_config.d/05-port.conf
sudo systemctl daemon-reload
sudo systemctl restart ssh.socket
ss -tlnp | grep 2222
Fedora и другие системы с SELinux
SELinux разрешает sshd слушать только помеченные порты, новый порт надо добавить в политику, иначе служба не запустится:
sudo semanage port -a -t ssh_port_t -p tcp 2222
sudo firewall-cmd --permanent --add-port=2222/tcp
sudo firewall-cmd --reload
sudo systemctl restart sshd
Во всех случаях сначала откройте новый порт в firewall и проверьте подключение по нему, и только потом закрывайте 22.
Кто может подключаться: firewall, VPN и Match
Лучшая защита SSH - не показывать его всему интернету. Варианты по возрастанию строгости:
- Разрешить порт только с известных адресов в firewall. Как это сделать на nftables, разобрано в статье про nftables. В Ubuntu то же самое делает
sudo ufw allow from 203.0.113.10 to any port 22 proto tcp. - Пускать только через VPN. Сервер слушает SSH только на адресе VPN-интерфейса, а наружу смотрит лишь порт WireGuard. Настройка VPN описана в материале о WireGuard.
- Разные правила для разных сетей через блок
Matchв конце конфига.
# слушать только VPN-адрес
ListenAddress 10.8.0.1
# в домашней сети разрешить пароль для старого устройства
Match Address 192.168.1.0/24
PasswordAuthentication yes
AuthenticationMethods any
Блоки Match ставьте в конец файла: всё, что ниже строки Match, относится только к нему. Если сервер поднимается вместе с VPN, проверьте, что интерфейс поднимается раньше sshd, иначе служба не сможет привязаться к адресу.
Защита от перебора: PerSourcePenalties и fail2ban
С версии 9.8 в OpenSSH встроен механизм PerSourcePenalties: адреса, которые часто рвут соединения на этапе входа или проваливают аутентификацию, временно перестают обслуживаться. Он включён по умолчанию, ничего настраивать не нужно. В 10.x механизм дорабатывали: срабатывания пишутся в журнал на уровне INFO, а попытки входа под несуществующим пользователем тоже наказываются.
Если нужна блокировка на уровне firewall и единая система для нескольких служб, ставят fail2ban:
# Debian, Ubuntu
sudo apt install fail2ban
# Fedora
sudo dnf install fail2ban
# Arch
sudo pacman -S fail2ban
Файл /etc/fail2ban/jail.local:
[sshd]
enabled = true
backend = systemd
port = ssh
maxretry = 5
findtime = 10m
bantime = 1h
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd
# разбанить свой адрес
sudo fail2ban-client set sshd unbanip 203.0.113.10
Параметр backend = systemd нужен в системах, где нет текстового /var/log/auth.log и журнал ведёт только journald: в Debian 13 и Fedora это так по умолчанию. При смене порта укажите его в строке port.
Журналирование: кто входил и кто пытался
Имя юнита различается: в Debian и Ubuntu это ssh, в Fedora и Arch sshd. Начиная с OpenSSH 9.8 записи о сеансах приходят от процесса sshd-session.
# всё по SSH за сегодня
sudo journalctl -u ssh --since today
# успешные входы с отпечатком ключа
sudo journalctl -u ssh -g 'Accepted publickey'
# неудачные попытки
sudo journalctl -u ssh -g 'Failed|Invalid user' --since '-1h'
# в реальном времени
sudo journalctl -u ssh -f
В строке успешного входа виден тип и отпечаток ключа, например ED25519 SHA256:..., а LogLevel VERBOSE добавляет подробности о неудачных попытках. Сравните его с выводом ssh-keygen -lf ~/.ssh/authorized_keys, и сразу станет понятно, каким ключом зашли. Это помогает, если на сервер ходит несколько человек и нужно понять, чей ключ отозвать.
Команда last показывает историю входов. В новых дистрибутивах она работает через базу wtmpdb, вывод от этого почти не изменился. Если журналы начали занимать слишком много места, ограничьте их по инструкции о настройке journald.
Второй фактор и ревизия ключей
Для сервера, к которому ходят с разных устройств, второй фактор добавляют двумя способами. Проще всего FIDO2-ключи ed25519-sk из раздела выше: без касания аппаратного токена вход невозможен, и PAM трогать не нужно. Второй путь - одноразовые коды TOTP через модуль PAM, например libpam-google-authenticator, и строка AuthenticationMethods publickey,keyboard-interactive. Он сложнее и требует включить KbdInteractiveAuthentication yes, поэтому настраивайте его при открытой запасной сессии.
Раз в несколько месяцев пересматривайте ~/.ssh/authorized_keys у всех пользователей. Ключи старых ноутбуков, уволенных коллег и CI-систем, которые больше не работают, удаляйте. Если учётной записью больше никто не пользуется, заблокируйте её, как описано в статье о команде passwd.
# найти все authorized_keys на сервере
sudo find /home /root -name authorized_keys -exec wc -l {} +
Полный список директив с описанием есть в официальной документации sshd_config проекта OpenSSH.
Частые вопросы
Нужно ли менять порт SSH?
Это не защита, а способ уменьшить шум в журналах. Основная защита - вход только по ключу, ограничение доступа по сети и отключённый вход root.
Почему PasswordAuthentication no не действует?
В sshd побеждает первое значение параметра. Скорее всего, его раньше задаёт другой файл в sshd_config.d, например 50-cloud-init.conf. Проверьте итог командой sudo sshd -T.
Как применить изменения sshd без разрыва сессии?
Проверьте конфиг через sudo sshd -t и выполните systemctl reload ssh (Debian, Ubuntu) или systemctl reload sshd (Fedora, Arch). Открытые сессии сохранятся.
Нужен ли fail2ban, если есть PerSourcePenalties?
Для одного сервера со входом по ключу встроенного механизма часто хватает. Fail2ban полезен, если нужна блокировка в firewall и защита нескольких служб сразу.
Как посмотреть неудачные попытки входа по SSH?
Выполните sudo journalctl -u ssh -g 'Failed|Invalid user'. В Fedora и Arch вместо ssh укажите sshd.
Документация и источники
- sshd_config(5), OpenSSH / OpenBSD, 2026
- OpenSSH Release Notes (9.8-10.6), OpenSSH, 2026
- OpenSSH Server, Ubuntu Server documentation, 2026
- OpenSSH, ArchWiki, 2026
Читайте также
- Как подключиться по SSH из Linux и Windows: от первого входа до туннелей
- Nftables: понятный firewall для домашнего компьютера и сервера
- WireGuard в Linux: свой VPN до домашней сети за полчаса
- Домашний сервер на Linux: хранение, резервные копии и сервисы
- Журнал systemd занимает диск: как очистить и ограничить journald
Команды проверены на актуальных версиях дистрибутивов на момент обновления. Перед изменением системных настроек сделайте резервную копию.