Мне часто приходится подключаться к серверу через ssh в ненадежной среде Wi-Fi. На сервере я запускаю экран, поэтому, если я отключусь, я могу снова подключиться и возобновить сеанс экрана, а также продолжить с того места, где я остановился, но потеря соединения по-прежнему является основной потерей времени: если соединение обрывается, когда я нахожусь на сервере, окно терминала имеет свойство зависать. Я должен убить эту вкладку, открыть новую, снова подключиться к серверу по ssh и возобновить сеанс экрана. Я пробовал это с запуском экрана на сервере и локальном экране. В любом случае он имеет тенденцию зависать, когда соединение обрывается.

Есть ли способ, которым я могу иметь что-то похожее на экран или, может быть, на сам экран, который будет автоматически пытаться повторно подключиться и поддерживать сеанс, поэтому мне не нужно продолжать повторное подключение вручную? Часто, когда я теряю соединение, я думаю, что это только на очень короткий период - может быть, меньше секунды.

Я использую Ubuntu 14.04 LTS, версия MATE. Благодарность

19
Max Williams 5 Июн 2018 в 11:36
4
Re «окно оболочки имеет тенденцию зависать»: это потому, что ваш локальный ssh ​​не знает, что соединение разорвано. Нажмите <Enter> и введите ~., чтобы ваша сторона разорвала соединение, и вы можете просто повторить последнюю команду ssh для повторного подключения (например, со стрелкой вверх или !!).
 – 
alexis
4 Июн 2018 в 23:41
Это звучит как более быстрый способ восстановить связь, спасибо! Хотя хотелось бы, чтобы это происходило автоматически...
 – 
Max Williams
5 Июн 2018 в 11:36

5 ответов

Вы можете посмотреть на использование mosh: https://mosh.org/

Вы можете настроить «переходный» сервер с надежным подключением к Интернету, к которому вы используете mosh для подключения, а затем иметь сеансы ssh с каждым сервером, которым вы управляете. Причина, по которой я предлагаю использовать переходный сервер, заключается в том, что вы можете не захотеть устанавливать mosh на серверах, которыми вы управляете.

Еще одним преимуществом mosh является то, что он основан на UDP, а не на TCP, и ваш сеанс может выдержать изменение IP-адреса, например, при переходе с WiFi на мобильное подключение к Интернету.

Просто чтобы было ясно, mosh не является заменой screen, а скорее ssh. По-прежнему рекомендуется использовать с ним screen, так как mosh сам по себе не дает возможности повторно подключиться к вашему сеансу, если клиент по какой-либо причине умирает.

23
muru 4 Июн 2018 в 18:57
Спасибо, это всего лишь один сервер (большую часть времени), и он принадлежит нам, поэтому я смогу установить Mosh. Я проверю это.
 – 
Max Williams
4 Июн 2018 в 10:59
На самом деле оказалось, что из-за того, что наш сервер довольно старый (или, я должен сказать, работает на старой Ubuntu), его слишком сложно установить. :(
 – 
Max Williams
4 Июн 2018 в 11:51
Сколько этому лет? Даже LTS 12.4 больше не поддерживается. И почему бы просто не попробовать скомпилировать его самостоятельно
 – 
phuclv
4 Июн 2018 в 12:33
Как я читал документы mosh, вам нужен mosh-server на каждом хосте, которым вы собираетесь управлять удаленно. Тем не менее, определенно интересно.
 – 
Wildcard
4 Июн 2018 в 12:43
1
Подключение к терминалу tmux через mosh для меня является наиболее стабильным решением.
 – 
Nemo
4 Июн 2018 в 14:47

Я использую tmux уже несколько лет и, по моему опыту, автоматически переподключается. По крайней мере, когда соединение прерывается только на относительно короткое время. Обратите внимание, что на самом деле я использую byobu с tmux в качестве серверной части. Я не знаю, является ли эта надежность функцией tmux или byobu или даже их комбинации, но я предлагаю вам попробовать оба варианта.

Я подключаюсь из своей локальной установки Arch к различным удаленным серверам Ubuntu через VPN. Я только что проверил это, отключив сетевой кабель, когда был подключен к пульту. Сеанс завис, но как только мой кабель был снова подключен, он возобновился без проблем.

Однако, когда я проверил, перезагрузив маршрутизатор, соединение не восстановилось. Я предполагаю, что это как-то связано с тем, как долго сеть была недоступна, но, похоже, она снова подключается, если она не работает всего несколько секунд.

Если это уместно, я делаю все это, используя terminator в качестве терминала. эмулятор.

Все три доступны в репозиториях Ubuntu:

sudo apt-get install tmux terminator byobu

Однако я совсем не уверен, что tmux или byobu лучше справляются с отключением ssh. Я только знаю, что по моему опыту, они часто возвращаются из-за коротких потерь связи. Это может быть связано с другими аспектами моей конфигурации.

3
terdon 4 Июн 2018 в 19:27
1
Когда вы перезапустили маршрутизатор, вам мог быть присвоен другой общедоступный IP-адрес, что приведет к разрыву соединения tcp. По моему опыту, ssh может быть очень устойчивым к периодическим отключениям сети, я не думаю, что это имеет какое-либо отношение к тому факту, что вы используете tmux в окне ssh.
 – 
rusty shackleford
4 Июн 2018 в 13:31
3
Я собирался сказать то же самое: даже с простым SSH вы можете иметь дело с коротким отключением, если TCP-соединение не прерывается. Что может случиться, если ваш интерфейс выключится, или какой-нибудь слишком усердный маршрутизатор убьет его (маршрутизаторы NAT могут забыть о состоянии NAT при перезагрузке и разорвать существующие соединения), или триггеры ClientAlive/ServerAlive, или... Однако я понятия не имею, что делает byobu.
 – 
ilkkachu
4 Июн 2018 в 13:34
Да, но OP, похоже, зависает при любом сбое соединения, а я нет. Но да, вы правы, я также вижу это с простым ssh и без tmux. Тем не менее, может экран с этим не справляется?
 – 
terdon
4 Июн 2018 в 13:56
2
tmux в основном более современная альтернатива screen, да. Когда я впервые начал работать, как сейчас, и нуждался в подобных вещах, мое беглое чтение показало, что tmux - лучший выбор в наши дни. Я также не на 100% уверен, что у него лучше управление потерянными соединениями, все, что я знаю, это то, что по моему опыту он восстанавливается после коротких сбоев. Я не знаю, связано ли это с tmux или с чем-то еще. Но кажется стоит попробовать :). Byobu — это, по сути, интерфейс для screen/tmux, а не эмулятор терминала с графическим интерфейсом. Однако это чрезвычайно полезно: byobu.org.
 – 
terdon
4 Июн 2018 в 15:56
2
Tmux ничего не делает с прерываниями соединения. Он работает с терминальным устройством, предоставляемым ssh. Все стоит и падает с подключением по ssh.
 – 
Jonas Schäfer
4 Июн 2018 в 19:03

Используйте параметры ssh ServerAlive, чтобы определить, когда соединение не удалось.

ServerAliveCountMax
Устанавливает количество активных сообщений сервера (см. ниже), которые могут быть отправлены без получения ssh(1) каких-либо сообщений от сервера. сервер. Если этот порог будет достигнут во время отправки сообщений сервера, ssh отключится от сервера, прекращение сеанса. Важно отметить, что использование активных сообщений сервера сильно отличается от TCPKeepAlive (ниже). Сообщения сервера в режиме реального времени отправляются по зашифрованному каналу и, следовательно, не могут быть подделаны. Параметр поддержания активности TCP, включенный TCPKeepAlive, можно подделать. Механизм «живой сервер» ценен, когда клиент или сервер зависят от знания того, когда соединение стало неактивным.

Значение по умолчанию — 3. Если, например, для ServerAliveInterval (см. ниже) установлено значение 15, а для ServerAliveCountMax оставить значение по умолчанию, если сервер перестанет отвечать, ssh отключится примерно через 45 секунд.

ServerAliveInterval
Устанавливает тайм-аут в секундах, по истечении которого, если данные не были получены с сервера, ssh(1) отправит сообщение по зашифрованному каналу для запроса ответа от сервера. Значение по умолчанию равно 0, что указывает на то, что эти сообщения не будут отправлены на сервер.

Таким образом, если вы установите ServerAliveInterval на 5, ssh автоматически отключится, если сеть пропадет на 15 секунд.

2
Barmar 5 Июн 2018 в 01:13
Чтобы принудительно прервать сеанс SSH, я нажимаю ~. (или сначала Enter, затем ~.), состоящую из: управляющего символа ~ и команды для разрыва сеанса .
 – 
imz -- Ivan Zakharyaschev
5 Июн 2018 в 01:15
@imz--IvanZakharyaschev Это предполагает, что вы можете сказать, что соединение зависло. Использование проверки активности SSH автоматически обнаружит сбой.
 – 
Barmar
5 Июн 2018 в 02:42
Звучит очень полезно, спасибо, я обязательно попробую это в следующий раз, когда окажусь в «ненадежной зоне».
 – 
Max Williams
5 Июн 2018 в 10:24
Да, верно. Я также думал о проблеме определения того, действительно ли соединение зависло, или я, нажимая что-то, могу случайно отправить эти ключи на удаленную сторону ... И я не знаю хорошего решения.
 – 
imz -- Ivan Zakharyaschev
6 Июн 2018 в 13:20

В подобных условиях я предпочитаю использовать eshell с TRAMP (через ssh) внутри Emacs. TRAMP позаботится о повторном подключении, когда это необходимо, не доставляя мне особых проблем с вводом нужных команд для удаленной оболочки.

Тем не менее, eshell не подходит в качестве терминала, т. е. для запуска команд, которые делают что-то особенное с терминалом или выполняются в течение значительного периода времени, непрерывно (инкрементно) что-то выводя.

По сути, начать использовать его в Emacs с помощью TRAMP довольно просто:

M-x eshell
cd /user@host:
2
imz -- Ivan Zakharyaschev 5 Июн 2018 в 01:14

Отказ от ответственности

Если ваше SSH-соединение не выдерживает кратковременных сбоев в работе сети, значит, происходит что-то еще, что не позволяет ssh и TCP выполнять свою обычную работу.

Подробнее см. ниже. Так или иначе:

Самое быстрое и самое грязное решение без зависимостей

Создайте сценарий оболочки следующим образом:

#!/bin/sh -

# Tune these numbers depending on how aggressively
# you want your SSH session to get reconnected.
timeout_options='-o ServerAliveInterval=4 -o ServerAliveCountMax=2'

# 255 is the status OpenSSH uses to signal SSH errors, which
# means we want to connect. All other exit statuses suggest
# an intentional exit.
status=255

# Keep opening the SSH connection and immediately dropping into
# `screen` until an intentional exit happens.
while [ "$status" = 255 ]
do
    ssh $timeout_options -t "$@" screen -dR
    status=$?
    # You can add a `sleep` command here or a counter or whatever
    # you might need as far as rate/retry limiting.
done
exit "$status"

Это просто запустит глупо-простой цикл, который пытается соединиться с ssh и подключиться к screen. Передайте хост или что-то еще, что вы обычно передаете своему вызову ssh в качестве аргументов командной строки.

Повторное подключение основано только на том, сообщает ли SSH об ошибке с подключением, что означает, что у него нет интеллекта для обнаружения ошибок, отличных от SSH, таких как «у вас буквально не включен Wi-Fi» или что-то еще, но это, вероятно, не имеет значения для ты.

Я предполагаю, что у вас есть ssh-agent или ключ SSH без парольной фразы, который позволит переподключениям просто работать без дополнительного ввода с вашей стороны.

Будет небольшая гонка, при которой, если вы нажмете ^C в течение нужной незаметной для человека доли секунды во время повторного подключения, вы можете в конечном итоге убить скрипт вместо того, чтобы передать ^C через клиентский терминал, поэтому, если вы подозреваете, что соединение зависло, не давите ^C слишком усердно.

Простейшее дополнительное программное решение

Вы можете попробовать программу autossh, которая должна быть доступна в вашем репозитории пакетов Ubuntu.

Если вам нужно собрать из исходного кода или проверить его, это единственная программа на C, которая компилируется без каких-либо дополнительных библиотек в качестве зависимостей, кажется, имеет больше интеллектуальных возможностей для проверки живости соединения, чем мой хак выше, и она также поставляется с помощью удобной команды сценария rscreen, которая автоматически присоединяется к screen.

Детали

Как ssh обычно восстанавливается

Просто для проверки, потому что я не люблю говорить вещи, не проверив себя, я провел небольшой тест, прежде чем ответить:

Я подключился к своему Wi-Fi с устройством Linux, установил SSH-подключение к другому устройству в моей локальной сети, убедился, что у меня есть работающее соединение ssh с другим концом (мог запускать команды и т. д.), затем на клиенте отключил WiFi (что привело к деконфигурации интерфейса: больше нет IP-адресов), ввел еще кучу символов в сеанс ssh (конечно, без ответа), а затем снова подключился к моему WiFi - переподключение на самом деле произошел сбой по крайней мере один раз из-за плохого сигнала и других факторов, затем, наконец, переподключение: я подождал около пяти секунд, пока сеанс ssh восстановится, ничего не произошло, поэтому я нажал еще одну клавишу, и сеанс ssh немедленно снова ожил, и все клавиши, которые я набрал во время отключения, появились в командной строке.

Видите ли, ssh просто записывает/читает в сетевой сокет TCP, пока ОС не сообщит, что что-то пошло не так, а TCP на самом деле очень устойчив к длительным обрывам соединения.

Предоставленный самому себе с настройками ядра по умолчанию, стек TCP в Linux будет счастливо терпеть полное молчание соединения в течение многих минут, прежде чем объявить соединение мертвым и сообщить об ошибке ssh - к тому времени, когда оно, наконец, сдастся, мы' разговаривать примерно около 30 минут или, по крайней мере, достаточно долго, чтобы пережить икоту соединения, длящуюся секунду или минуту.

Под прикрытием стек Linux TCP постепенно повторяет сообщения с все более и более длительными задержками, а это означает, что к тому времени, когда ваше соединение действительно восстановится, вы можете столкнуться с дополнительной задержкой до того, как ваш ssh сеанс, кажется, придет " снова живой».

Почему это иногда ломается

Часто что-то активно вызывает закрытие соединения после некоторого значительно более короткого периода бездействия, чем допустимый стек TCP, а затем не сообщает об этом состоянии соединения вашему ssh клиенту.

Вероятные кандидаты включают:

  1. Брандмауэры или NAT-маршрутизаторы, которые должны использовать память для запоминания каждого действующего TCP-соединения. В качестве оптимизации и некоторого смягчения последствий DOS-атак они иногда просто забывают ваше соединение, а затем молча игнорировать последующие пакеты для него, потому что пакеты в середине соединения, когда вы не помните существующее соединение, выглядят недействительными.

  2. Брандмауэры/маршрутизаторы с лучшим поведением вставят пакет TCP RST, который обычно проявляется в виде сообщения об ошибке connection reset by peer, но пакет сброса является фаер-и-забытым, поэтому, если соединение с вашим клиентом все еще имеет проблемы на в этот момент и также сбросит пакет сброса, ваш клиент будет думать, что соединение все еще живо.

  3. На самом сервере может быть политика брандмауэра, которая автоматически отбрасывает неожиданные пакеты, что прерывает попытки клиента возобновить соединение всякий раз, когда сервер считает, что соединение закрыто, а клиент этого не делает: ваш клиент продолжает пытаться продолжить соединение, но сервер просто игнорирует его, потому что нет активного соединения, которому принадлежат эти пакеты в состоянии брандмауэра сервера.

    Поскольку вы используете Linux, внимательно проверьте iptables/ip6tables вашего сервера (или nft, если вы используете новый материал), чтобы точно определить, что вы разрешаете, а что отбрасываете. Очень часто разрешаются новые/установленные/связанные пакеты через порт TCP SSH, но не "недействительные" одни - если вы молча удаляете все, что не разрешено, эта обычная настройка может вызвать такие зависания после коротких проблем с подключением.

  4. Сам ваш SSH-сервер может быть настроен на закрытие соединения после определенного периода бездействия, используя одну из опций OpenSSH для TCP- или SSH-пакетов проверки активности клиента. Само по себе это не приведет к бесконечным зависаниям, но может привести к одному из состояний, описанных выше.

  5. Возможно, вы просто не даете ему достаточно времени, чтобы «отключиться» самостоятельно после того, как вы попали в состояние, когда ваш сеанс ssh зависает.

1
mtraceur 6 Июн 2018 в 03:39