3 альтернативы SSH для нестабильных соединений
Сравните Mosh, Eternal Terminal и autossh для нестабильных SSH-соединений: UDP, TCP-переподключение, требования к серверу и связку с tmux.
Mosh, Eternal Terminal и autossh решают одну и ту же проблему тремя разными способами: Mosh синхронизирует состояние терминала поверх UDP и следует за вами при смене IP-адреса, Eternal Terminal переподключается к той же сессии по TCP, а autossh автоматически перезапускает SSH, но каждый раз создаёт новую сессию.
Если вам когда-нибудь доводилось наблюдать, как деплой замирает на середине из-за того, что ваш поезд въехал в тоннель, вы знаете, что будет дальше: терминал зависает, вы сидите и надеетесь, а через минуту смотрите на client_loop: send disconnect. Wi-Fi в кафе, раздача с телефона и нестабильный VPN делают с сессией одно и то же. Вопрос не в том, стоит ли заменять обычный SSH для интерактивной работы, а в том, какой из этих трёх инструментов подходит вашей сети и вашему уровню доступа к серверу. В этой статье они сравниваются по одному критерию: что на самом деле происходит с вашей сессией, когда связь обрывается.
Ключевые выводы
- Mosh синхронизирует состояние терминала поверх UDP, Eternal Terminal переподключается к той же сессии по TCP, а autossh перезапускает SSH, каждый раз создавая новую сессию.
- Заблокирован ли UDP между вами и сервером — вот решающий фактор при выборе между Mosh и Eternal Terminal.
- autossh работает полностью на стороне клиента, и на сервере ему не нужно ничего, кроме sshd, но каждое переподключение приводит в новый шелл, поэтому для практической пользы ему необходим tmux или Zellij.
- tmux и Zellij надстраиваются поверх всех трёх инструментов: они поддерживают процессы живыми на сервере, тогда как эти инструменты поддерживают живым ваш путь до сервера.
Что ломается при обрыве связи?
SSH-сессия живёт внутри одного TCP-соединения, привязанного к IP-адресу вашего клиента, поэтому, когда сеть пропадает или адрес меняется, соединение умирает и уносит с собой удалённый шелл. TCP идентифицирует соединение по четвёрке из адреса и порта источника и назначения; новый IP из новой Wi-Fi-сети означает новую четвёрку, о которой сервер никогда не слышал. Как только keepalive-пакеты перестают проходить или сокет выдаёт ошибку, sshd убивает шелл и все запущенные в нём процессы переднего плана. Каждый из трёх инструментов ниже атакует своё звено этой цепочки.
Mosh: синхронизация состояния поверх UDP
Что происходит при сбое
Mosh заменяет модель байтового потока синхронизацией состояния: клиент и сервер хранят по снимку экрана, а протокол State Synchronization Protocol, разработанный в Mosh, приводит их к общему виду через зашифрованные UDP-датаграммы. Поскольку сервер просто отправляет ответ на адрес источника последнего аутентифицированного пакета, роуминг при смене IP происходит автоматически: усыпите ноутбук, переключитесь на другую сеть — и сессия возобновится без какого-либо шага переподключения. Предиктивное локальное эхо показывает нажатия клавиш немедленно, не дожидаясь ответа сервера.
Что для этого нужно
Mosh требует наличия бинарника mosh-server на удалённой машине (без прав суперпользователя и без постоянно работающего демона: обе половины запускаются от вашего имени и завершаются вместе с сессией), а также доступности UDP. Mosh аутентифицируется через обычный SSH-вход, после чего по умолчанию использует UDP-порт из диапазона 60000–61000 (первый доступный порт начиная с 60001), который должен быть разрешён на файрволах. Опции пробрасываются в нижележащий ssh:
mosh --ssh="ssh -i ~/.ssh/other_key" user@host
В чём он проигрывает
Если UDP заблокирован, Mosh не работает вообще; отката на TCP не предусмотрено. Кроме того, Mosh синхронизирует только символы, находящиеся на экране в данный момент, поэтому история прокрутки теряется, и FAQ самого проекта отсылает вас к screen или tmux на удалённой стороне. В сравнении двух инструментов от Eternal Terminal добавляется, что Mosh не может работать с control mode в tmux (tmux -CC), что важно для пользователей iTerm2. Самая свежая версия на странице релизов проекта — 1.4.0 от октября 2022 года.
Eternal Terminal: та же сессия поверх TCP
Что происходит при сбое
Eternal Terminal восстанавливает соединение по обычному TCP, не разрушая то, чем вы занимались, включая запущенную сессию tmux, так что обрыв связи стоит вам паузы, а не работы. Поскольку он никогда не выходит за пределы TCP, он работает именно в тех сетях, где Mosh неприменим: за корпоративными файрволами, отбрасывающими UDP, и на маршрутах, вынуждающих пропускать трафик через TCP-прокси.
Что для этого нужно
Eternal Terminal требует демона на стороне сервера. README проекта устанавливает два предварительных условия: рукопожатие и шифрование выполняет ssh, поэтому ssh user@hostname должен работать до того, как заработает ET, а серверная часть слушает TCP-порт 2022, если вы его не измените. Установка: brew install et на macOS или в Ubuntu:
sudo add-apt-repository ppa:jgmath2000/et
sudo apt-get update
sudo apt-get install et
Проверить демон можно командой systemctl status et.
В чём он проигрывает
Переподключение по TCP означает отсутствие магии роуминга и локального эха: на канале с высокой задержкой набор текста по-прежнему ощущается как в SSH. А поскольку ему нужен установленный с правами root демон и открытый порт, он неприменим на машинах, где вы не можете устанавливать ПО.
autossh: автоматический перезапуск, новая сессия
Что происходит при сбое
autossh оборачивает ssh и следит за запущенным им процессом, запуская замену всякий раз, когда тот завершается или перестаёт отвечать. Каждое переподключение — это совершенно новая SSH-сессия, поэтому без мультиплексора на сервере всё, что вы запускали, будет потеряно к моменту восстановления связи.
Что для этого нужно
autossh не требует на сервере ничего, кроме работающего sshd, что делает его единственным из трёх вариантом для машин, где вы не можете устанавливать ПО. Установка на стороне клиента:
sudo apt install autossh # Debian/Ubuntu
sudo dnf install autossh # Fedora/RHEL family (may need EPEL)
brew install autossh # macOS
В чём он проигрывает
Он восстанавливает соединение, а не сессию. Кроме того, он зависит от того, заметит ли ssh сбой: man-страница рекомендует ServerAliveInterval и ServerAliveCountMax, чтобы клиент быстро сдавался, как только канал умер.
tmux или Zellij сверху
tmux и Zellij не заменяют ни один из этих инструментов: они поддерживают ваши процессы живыми на сервере, тогда как Mosh, Eternal Terminal и autossh поддерживают живым ваш путь до сервера, и эти два слоя сочетаются. Zellij — терминальный мультиплексор, который управляет сессиями, панелями и вкладками и надстраивается поверх удалённого соединения так же, как это делает tmux.
autossh вместе с tmux — минимальная рабочая конфигурация, поскольку она заново подключается к постоянной сессии при каждом перезапуске:
autossh -M 0 -o "ServerAliveInterval 10" -o "ServerAliveCountMax 3" \
-t user@host "tmux new -A -s main"
-M 0 отключает порт мониторинга autossh, чтобы тот полагался на собственное завершение ssh, а tmux new -A -s main каждый раз подключается к сессии main (или создаёт её). Такая связка полезна и остальным: tmux даёт историю прокрутки, которой лишён Mosh, а Eternal Terminal явно проводит сессию tmux через обрывы связи.
Как выбрать среди этих альтернатив SSH?
Задайте три вопроса по порядку. Заблокирован ли UDP между вами и сервером? Если да, Mosh отпадает; устойчивым выбором становится Eternal Terminal. Можете ли вы что-либо установить на сервере? Если нет, autossh вместе с tmux — ваш единственный ход. В остальных случаях выбирайте по ощущениям: Mosh — для роуминга и мгновенного эха на плохих каналах, Eternal Terminal — если вам нужна настоящая история прокрутки или tmux -CC.
| Mosh | Eternal Terminal | autossh | |
|---|---|---|---|
| Модель восстановления | Синхронизация состояния поверх UDP, роуминг между IP | Переподключение к той же сессии по TCP | Перезапуск ssh, новая сессия |
| Требования к серверу | Бинарник mosh-server, открытый UDP | Демон с правами root, TCP-порт 2022 | Только sshd |
| Основное ограничение | Нет UDP — нет сессии | Нет локального эха | Сессия теряется без tmux |
Инструмент выбирается тем сценарием отказа, который вы не готовы терпеть. Попробуйте сначала Mosh в открытой сети, держите Eternal Terminal для закрытых, а autossh -M 0 с именованной сессией tmux добавьте в алиас шелла уже сегодня — это улучшит работу с каждой машиной, куда вы и так заходите по ssh.
Часто задаваемые вопросы
Работает ли Mosh через промежуточный SSH-хост (jump host) или бастион?
Нет. В Mosh нет встроенной поддержки [SSH-туннелей и бастион-хостов](https://docs.blink.sh/advanced/advanced-mosh). Промежуточный хост может обеспечить первоначальный SSH-вход, но зашифрованный UDP-трафик затем должен достигать целевой машины напрямую, а сам по себе jump-сервер этого не обеспечивает. В сетях, доступных только через бастион, autossh работает без изменений, поскольку он запускает обычный ssh, поддерживающий ProxyJump.
Настолько ли Mosh безопасен, как обычный SSH?
Вход по-прежнему выполняется через SSH. После этого Mosh шифрует и аутентифицирует каждую UDP-датаграмму с помощью [AES-128 в режиме OCB3](https://mosh.org/) — схемы аутентифицированного шифрования. SSH используется только для обмена ключами в начале, поэтому уязвимость в SSH затронула бы этот короткий этап установки соединения, а не длительную сессию Mosh. Ваши существующие SSH-ключи и проверка хоста применяются без изменений.
Может ли autossh поддерживать живыми проброс портов SSH, а не только интерактивные шеллы?
Да, постоянные туннели — одно из самых распространённых применений autossh. Запускайте его с -N, чтобы удалённая команда не выполнялась, с -M 0, чтобы отключить порт мониторинга, и с вашими обычными флагами проброса -L или -R; пример в самой man-странице сочетает -f -M 0 -N с ServerAliveInterval и ServerAliveCountMax. Туннель не хранит состояния шелла, поэтому ограничение с новой сессией здесь не действует: autossh просто заново устанавливает проброс.