Вход по ssh, который месяцами работал ровно, в один вечер начинает отвечать отказом. Первая реакция почти у всех одинаковая: перезагрузка машины. Перезагрузка редко помогает, потому что сервер чаще всего продолжает работать, а ломается один конкретный слой: порт, маршрут, проверка подлинности или блокировщик. Отказ почти никогда не бывает немым, клиент в подробном режиме показывает этап остановки, а серверный журнал проверки подлинности называет причину своими словами. Ниже разобран рабочий путь от сообщения на клиенте до локальной консоли, с командами для каждого шага и разбором самых частых записей журнала.
Три сценария отказа соединения и их различение по поведению клиента
Прежде чем что-то менять на сервере, стоит потратить минуту на наблюдение. Мгновенный отказ и долгое молчание говорят о принципиально разных поломках, и лечение у них противоположное.
Первый сценарий: сообщение "Connection refused" приходит сразу же. Сервер ответил, но на порту 22 его никто не слушает, значит служба остановлена, либо слушает другой порт, либо привязана к другому адресу. Второй сценарий: долгая тишина, а за ней "Connection timed out". Пакеты исчезают где-то по пути, и подозревать нужно маршрут, фильтр пакетов на самом сервере, внешнюю панель хостинга или опечатанный адрес. Третий сценарий: соединение строится, сервер присылает баннер, а затем отказывает во входе сообщением "Permission denied". Сеть здесь ни при чём, дело в проверке подлинности.
Быструю проверку порта и маршрута выполняют без ssh:
nc -zv 192.168.10.20 22
ping -c 3 192.168.10.20
Если nc получает отказ мгновенно, вопрос к службе и порту. Если nc молчит, а ping проходит, пакеты до машины доходят, но порт прикрыт фильтром. Если молчат оба, проблема в маршруте или в самой машине. Тонкость напоследок: ответы icmp многие администраторы отключают сознательно, поэтому тишина ping ничего не доказывает.
Полный порядок действий при внезапном отказе входа складывается из шести шагов:
- подключение в подробном режиме с фиксацией этапа остановки;
- чтение журнала проверки подлинности на сервере;
- проверка прав на каталог ключей и файл authorized_keys;
- проверка конфигурации sshd с синтаксическим контролем;
- просмотр списков блокировщика после чужих попыток подбора;
- вход через локальную консоль при полной недоступности сети.
Порядок не случаен: каждый шаг дешевле следующего, а большинство поломок обнаруживается на первых трёх.
Подробный режим клиента ssh и чтение этапов установления связи
Обычный запуск ssh сообщает пользователю только итог, подробный режим раскрывает механику построчно:
ssh -vv Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в браузере должен быть включен Javascript.
Ключи -v, -vv и -vvv отличаются глубиной детализации, для первичной диагностики хватает и одного уровня. Каждая строка вывода начинается с префиксом debug1, по которому удобно отделять этапы. Чтение строится по цепочке: строка "Connection established" означает, что tcp соединение построено и порт открыт. Строка "Remote protocol version 2.0" фиксирует обмен баннерами, после неё сетевой слой можно исключать из подозреваемых. Дальше идут согласование шифрования, список допустимых способов входа "Authentications that can continue", предложение ключа "Offering public key" и финальное решение сервера.
Остановка на конкретной строке и есть диагноз. Если вывод обрывается до баннера, вопрос к сети и порту. Если всё прошло, а ключ отвергнут строкой "Server refused our key", путь ясен: сервер получил ключ, но отказал ему в доверии, и причину искать нужно в правах и конфигурации. Отдельная ловушка прячется в агенте ключей: когда агент держит много ключей, клиент отправляет их по очереди, сервер тратит попытки на каждый и закрывает соединение сообщением о превышении их числа. Устраняется явным указанием ключа:
ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в браузере должен быть включен Javascript.
Локальный файл конфигурации клиента ~/.ssh/config заслуживает отдельного подозрения. Параметры из него применяются молча: имя пользователя, порт, путь к ключу, псевдоним хоста. Небольшая правка в нём меняет поведение всех новых подключений, и со стороны выглядит так, будто сервер сам стал отказывать. Проверка дешёвая и обратимая: временно убрать файл и повторить вход с явными параметрами.
mv ~/.ssh/config ~/.ssh/config.backup
ssh -p 22 -i ~/.ssh/id_ed25519 Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в браузере должен быть включен Javascript.
Журнал проверки подлинности на сервере и расшифровка типовых записей отказа
Клиент показывает, где остановилось соединение, а сервер объясняет, почему. Записи службы sshd живут в /var/log/auth.log на дистрибутивах семейства Debian и в /var/log/secure на семействе Red Hat, а на системах с systemd те же события доступны через journalctl. Основные команды для чтения:
grep sshd /var/log/auth.log | tail -n 40
grep "Failed password" /var/log/auth.log | tail -n 10
journalctl -u ssh -n 100 --no-pager
Читать нужно записи, совпадающие по времени со своей попыткой и по адресу с машиной клиента. Часы на двух машинах редко совпадают идеально, минуту расхождения списывают на сдвиг часов, а ориентиром служит характер отказа.
Частые строки читаются без словаря. Запись "Failed password for deploy" говорит, что пароль не подошёл, но сервер его честно сравнивал. Строка "Failed password for invalid user admin" с чужих адресов означает, что к машине идёт автоматический перебор имён, а такого пользователя не существует. Запись "User deploy not allowed because not listed in AllowUsers" указывает на запрет списком, обычно появившийся после чьей-то правки конфигурации. Строка "Authentication refused: bad ownership or modes for directory /home/deploy" прямо называет слишком открытые права на каталог. Сообщение о превышении числа попыток закрывает соединение до завершения проверки.
Полезно помнить и вид успеха: строка "Accepted publickey for deploy" описывает нормально прошедший вход. Если она была утром и исчезла вечером, момент поломки легко датировать по соседним записям. Когда текущий файл уже перекрыт новыми событиями, нужную запись ищут в архивах ротации:
zgrep "Failed password" /var/log/auth.log.2.gz
Права на каталог ключей и файл authorized_keys как частая причина внезапного отказа
Самая коварная причина внезапного отказа не имеет отношения ни к сети, ни к паролям. Служба sshd со включённым режимом StrictModes отказывается доверять ключам, если права на домашний каталог, каталог .ssh или файл authorized_keys слишком открыты. Правка настроек тут ни при чём: достаточно скопировать ключи с сохранением прав, перенести домашний каталог или восстановить его из архива, и вход по ключу закрывается без единого предупреждения со стороны сервера.
Проверка занимает секунды:
ls -ld /home/deploy /home/deploy/.ssh /home/deploy/.ssh/authorized_keys
Норма известна давно: домашний каталог без прав записи для группы и остальных, каталог .ssh с правами 700, файл authorized_keys с правами 600, владелец всего набора сам пользователь. Восстановление выглядит так:
chmod go-w /home/deploy
chmod 700 /home/deploy/.ssh
chmod 600 /home/deploy/.ssh/authorized_keys
chown -R deploy:deploy /home/deploy/.ssh
Клиентская сторона держит зеркальное требование. Если права на закрытый ключ слишком открыты, ssh печатает предупреждение о незащищённом файле и молча игнорирует ключ, поэтому вход заканчивается отказом. Исправляется той же командой chmod 600 на файл закрытого ключа. Внезапность таких отказов объясняется просто: права меняются не в момент входа, а при копировании, синхронизации или разархивировании, и связь события с отказом на глаз не видна. Если после восстановления прав вход по-прежнему закрыт, виновата конфигурация, её разбирает следующий раздел.
Синтаксический контроль конфигурации sshd и безопасный порядок перезапуска службы
Правки конфигурации входят в число лидеров по числу внезапных отказов. Одна строка в /etc/ssh/sshd_config или в подключённом файле из каталога sshd_config.d способна закрыть вход целиком: смена порта, списки AllowUsers и DenyUsers без нужного имени, отключение входа по ключам параметром PubkeyAuthentication no, отключение входа по паролю, привязка к одному адресу через ListenAddress. Опечатка в параметре не всегда останавливает службу, иногда конфигурация применяется частично, и поведение становится непредсказуемым.
Перед любой правкой и после неё работает правило двух сессий: текущее подключение не закрывать, изменения проверять из второго терминала. Синтаксис проверяет режим тестовой конфигурации, эффективные значения показывает режим дампа:
/usr/sbin/sshd -t
/usr/sbin/sshd -T | grep -Ei 'port|allowusers|pubkeyauthentication|passwordauthentication'
ss -tlnp | grep sshd
Режим -t молчит, когда синтаксис в порядке, и печатает номер проблемной строки при ошибке. Режим -T выдаёт эффективную конфигурацию целиком, со всеми значениями, которые реально применятся. Команда ss подтверждает фактическое состояние: какой порт слушает служба и слушает ли она вообще. Имя службы в systemd зависит от дистрибутива, где-то это ssh, где-то sshd, поэтому перед перезапуском имя стоит уточнить командой systemctl status.
Блокировщик входа после чужих попыток подбора и проверка его списков
Журналы публичных серверов переполнены строками "Failed password for invalid user", автоматический перебор идёт к любой машине с открытым портом круглосуточно. Против перебора ставят блокировщики вроде fail2ban, которые после серии неудач создают правило фильтрации для адреса источника. Логика защиты разумна, но у неё есть обратная сторона: под правило иногда попадает честный адрес, например общий адрес провайдера, за которым сидят сотни абонентов, либо собственный адрес после серии опечаток в пароле.
Признак на клиенте своеобразен: соединение доходит до обмена баннерами и обрывается до запроса способа входа. Проверить состояние блокировщика на сервере:
fail2ban-client status
fail2ban-client status sshd
Первая команда перечисляет активные наборы правил, вторая показывает статистику и список закрытых адресов по службе входа. Снять блокировку своего адреса позволяет команда:
fail2ban-client set sshd unbanip 203.0.113.7
Помимо fail2ban, встречаются устаревший механизм hosts.deny, самодельные правила в nftables или iptables и ограничения на стороне панели хостинга. Последние на самой машине не видны, проверяются только из панели, поэтому при загадочном обрыве соединения туда тоже стоит заглянуть. Перед снятием блокировки полезно понять её причину: если журнал показывает непрерывный перебор с адреса провайдера, правило вернётся быстро, и вход придётся выполнять с другого адреса.
Локальная консоль при полной недоступности сети и три тихие причины отказа
Когда сеть недоступна целиком, остаётся путь последнего доступа: локальная консоль. У облачных и выделенных машин это экран KVM или VNC в панели хостинга, у железных серверов аппаратная консоль управления или физический терминал. Консоль не зависит ни от сети, ни от службы ssh, поэтому проходит там, где ssh бессилен. Внутри действуют по знакомой цепочке: состояние службы, слушаемый порт, диск, журнал, перезапуск после исправления.
systemctl status sshd
ss -tlnp | grep sshd
df -h
journalctl -u ssh -n 100 --no-pager
Список тихих причин, которые находятся только изнутри, короткий, но обидный. Первая: переполненный диск. Когда место в разделе с /var заканчивается, журналы не пишутся, файлы блокировок не создаются, и вход отказывает без единой внятной записи. df -h покажет заполненные разделы, лечение сводится к чистке, например сжатию старых записей журнала systemd:
journalctl --vacuum-size=200M
Вторая: медленный обратный поиск имён. Параметр UseDNS заставляет службу при каждом входе искать имя по адресу клиента, и когда dns отвечает медленно, вход зависает надолго, а затем отказывает. Отключается строкой UseDNS no с проверкой синтаксиса и перезапуском службы.
Третья: истёкший пароль учётной записи. Механизм pam способен блокировать вход даже с верным ключом, если срок пароля истёк или учётная запись закрыта. Команда покажет сроки:
chage -l deploy
После установки свежего пароля командой passwd и снятия блокировки командой usermod -U вход обычно восстанавливается сразу. Финальный совет: путь аварийного доступа стоит проверять заранее, в спокойной обстановке, потому что в вечер отказа проверять консоль уже поздно.