Connection refused и Connection timed out выглядят как близнецы — SSH в обоих случаях не подключился, — но это противоположные находки, указывающие на разные половины стека. Понимание того, с которой из них вы имеете дело, вдвое сокращает список подозреваемых ещё до того, как вы наберёте хоть одну диагностическую команду. Это рутина на две минуты: что доказывает каждая ошибка, единственный зонд, отделяющий их от всего прочего, и чек-лист для каждой ветки. (Про ошибки, которые случаются после успешного TCP-соединения — сбои аутентификации, предупреждения о ключе хоста, умирающие сессии, — см. дешифратор.)
| Ошибка | Что доказывает | Вероятная причина | Первая команда |
|---|---|---|---|
Connection refused | Хост поднят и активно сказал «нет» (вернулся RST) | На этом порту ничего не слушает или правило файрвола REJECT | ss -tlnp | grep sshd из консоли |
Connection timed out | Ничего не вернулось вообще — тишина на пути | Неверный IP, хост лежит или молчаливый DROP (облачная security group / файрвол) | nc -vz host 22, затем проверьте облачный файрвол |
Что на самом деле доказывает каждая ошибка
Connection refused означает, что машина вам ответила. Ваш TCP SYN дошёл до живого хоста, и хост активно сказал «нет» — вернулся пакет RST или ICMP port-unreachable. Это неожиданно много хороших новостей: IP правильный, маршрут работает, хост поднят, и ничто на пути не съедает ваши пакеты. Проблема узкая: на этом порту ничего не слушает или правило файрвола его отклоняет (а не отбрасывает).
Connection timed out означает тишину. Ваши пакеты ушли, и ничего обратно не пришло. Это почти ничего не доказывает про сервер — он может лежать, IP может быть неверным или (чаще всего) что-то между вами и им молча отбрасывает пакеты: облачная security group, файрвол с политикой DROP, чёрная дыра NAT или VPN.
Одна мнемоника: refused = машина с вами заговорила; timed out = так и не заговорила. Refused — проблема хоста. Timed out — обычно проблема пути.
Шаг 1: зондируйте порт, а не хост
Пропустите ping как первый шаг — он проверяет не то в обе стороны. Хост, отвечающий на ping, всё равно может отбрасывать порт 22 (облачные файрволы фильтруют по портам), а хост, игнорирующий ping, может прекрасно обслуживать SSH (ICMP блокируют повсюду). Ping не доказывает ничего, что вам нужно.
Зондируйте сам порт:
nc -vz example.com 22
(Нет netcat? Подойдёт telnet example.com 22 — любой вывод, начинающийся с SSH-2.0-..., означает, что sshd ответил.) Три исхода:
Connection refused— переходите к ветке refused ниже.- Висит, затем таймаут — переходите к ветке timed out.
- Успех — с TCP всё хорошо, и ваша проблема внутри самого SSH: не тот пользователь или ключ (у
Permission denied (publickey)есть свой гайд (на английском)), несовпадение ключа хоста или что-то, чтоssh -vназовёт прямо.
Ветка refused: найдите, что (не) слушает
Вам понадобится другой способ попасть на коробку — веб-консоль провайдера существует как раз для такого момента.
Запущен ли sshd?
systemctl status sshd # the unit is "ssh" on Debian/Ubuntu
Если он мёртв, не просто перезапускайте — проверьте почему: journalctl -u sshd (или -u ssh) покажет, как он завершился. Частая причина — правка конфига, которая не парсится; sshd -t проверяет файл и называет плохую строку ещё до того, как вы перезапуститесь в тот же сбой.
Слушает ли он там, где вы думаете?
sudo ss -tlnp | grep sshd
В этом выводе прячутся две подлянки. Порт: кто-то перенёс SSH на 2222, а вы стучитесь в 22 — подключайтесь через ssh -p 2222, затем закрепите это для каждого хоста в ~/.ssh/config (на английском), чтобы больше не выводить заново. Адрес: строка ListenAddress может привязать sshd к одному интерфейсу, так что он отвечает на приватном IP и отклоняет на публичном.
Не отклоняет ли локальный файрвол? sudo ufw status, sudo iptables -L -n или nft list ruleset — ищите правила REJECT, покрывающие ваш порт. Правило REJECT даёт ровно эту ошибку: хост поднят, sshd может даже слушать, а файрвол отвечает за него.
Не забанили ли вас? Действие fail2ban по умолчанию отклоняет, так что бан выглядит как Connection refused — только с вашего IP. Признак: с мобильной точки доступа работает, а с вашей сети — нет. Из консоли: fail2ban-client status sshd, затем fail2ban-client unban <your-ip> — и исправьте то, что достаточно часто повторяло неверные данные, чтобы заработать бан.
Ветка timed out: найдите, где умирают пакеты
Сначала подтвердите адрес. Стыдно ровно один раз. ssh -v печатает IP, на который он реально звонит — сверьте его с панелью провайдера. Устаревший DNS после миграции и elastic IP, не переживший остановку инстанса, — оба классика.
Дальше проверьте облачный файрвол, потому что в большинстве случаев это и есть ответ. Security groups (AWS), NSG (Azure) и правила файрвола VPC (GCP) по умолчанию отбрасывают входящий трафик — молча, что как раз и есть таймаут. Ищите входящее правило, разрешающее TCP 22 с вашего адреса. Коварный вариант: правило, привязанное к «My IP» несколько месяцев назад, а ваш IP с тех пор сменился. Сетевые ACL на уровне подсети — второй, менее посещаемый слой, в который стоит заглянуть, когда security group кажется правильной.
Трассируйте путь, когда облачные правила в порядке:
traceroute example.com # mtr example.com for a live view
sudo traceroute -T -p 22 example.com # TCP to the actual port — closest to the truth
Обычный traceroute использует UDP или ICMP, которые файрволы обрабатывают иначе, чем TCP 22 — форма -T -p 22 проверяет то, что реально переживает SSH. Где хопы перестают отвечать — примерно там ваши пакеты и умирают.
Подозревайте свою сторону. Гостевые сети отелей, кафе и офисов регулярно блокируют исходящий 22, а корпоративные VPN его перенаправляют или отбрасывают. Тест на изоляцию — мобильная точка доступа: если там SSH работает, с вашим сервером всё в порядке, а проблема — в сети, в которой вы были.
Файрвол с политикой DROP на самом хосте снаружи выглядит так же, как отбрасывание на стороне облака — если у вас есть доступ к консоли, проверьте iptables/nftables и на самой коробке.
Экзотика: port knocking. Сервер с knockd отбрасывает всё, пока не увидит секретную последовательность попыток подключения на других портах. Если коробку настраивал предшественник и каждый порт таймаутит отовсюду, поспрашивайте у коллег, прежде чем спалить полдня на теории о маршрутизации.
Запомните версию на две минуты
Вся рутина хорошо сжимается: зондируйте порт через nc -vz. Refused → зайдите через консоль, проверьте sshd, порт прослушивания, правила REJECT, fail2ban. Timed out → подтвердите IP, проверьте облачную security group, затем traceroute и собственную сеть. Ping в ней не фигурирует нигде.
Повторяющиеся факты — какой порт, какой пользователь, какому хосту нужны keepalive — живут в ~/.ssh/config (на английском), а не в вашей памяти. А часть диагностики может быть постоянным состоянием, а не метаниями посреди инцидента: Termalin хранит порт, пользователя, ключ и настройки keepalive вместе с каждым сохранённым хостом и показывает живой статус по каждому — так что «а коробка вообще жива?» и «на каком же порту это было?» получают ответ ещё до подключения, а сервер, который слушает только на 2222, перестаёт быть тем, что вы заново открываете для себя каждый квартал.
Termalin — бесплатный кроссплатформенный SSH-клиент, который хранит порты, пользователей, ключи и keepalive каждого хоста вместе с хостом и показывает живой статус хоста — скачайте его или полистайте полный список возможностей.