12k
All articles

不安定な接続に対する3つのSSH代替手段

不安定なSSH接続向けにMosh、Eternal Terminal、autosshを比較。UDP、TCP再接続、サーバー要件、tmux併用まで解説。

OpenReplay Team
OpenReplay Team
不安定な接続に対する3つのSSH代替手段

Mosh、Eternal Terminal、autosshは同じ障害を3つの異なる方法で解決します。MoshはUDP上で端末の状態を同期し、IPアドレスの変更にも追従します。Eternal TerminalはTCP上で同一セッションに再接続します。autosshはSSHを自動的に再起動しますが、毎回新しいセッションが始まります。

電車がトンネルに入った瞬間にデプロイが途中で固まるのを見たことがあるなら、その後の展開はご存じでしょう。端末が固まり、祈るような気持ちで待ち、1分後には client_loop: send disconnect を眺めているわけです。カフェのWi-Fi、テザリング中のスマートフォン、不安定なVPN。いずれもセッションに対して同じ結果をもたらします。問題は、対話的な作業において素のSSHを置き換えるべきかどうかではなく、これら3つのツールのうちどれが自分のネットワーク環境とサーバへのアクセス権限に合っているかです。本記事では、1つの軸で比較します。回線が切れたとき、セッションに実際に何が起こるのかという軸です。

要点

  • MoshはUDP上で端末の状態を同期し、Eternal TerminalはTCP上で同一セッションに再接続し、autosshは毎回新しいセッションでSSHを再起動する。
  • MoshとEternal Terminalのどちらを選ぶかは、自分とサーバの間でUDPがブロックされているかどうかが決定要因になる。
  • autosshは完全にクライアント側で動作し、サーバ側にはsshd以外何も必要としないが、再接続ごとに新しいシェルになるため、実用的に使うにはtmuxやZellijが必要になる。
  • tmuxとZellijは3つのツールすべての上に重ねて使える。これらのツールがサーバへの経路を維持する一方で、tmuxとZellijはサーバ上のプロセスを生かし続ける。

回線が切れたとき、何が壊れるのか

SSHセッションは、クライアントのIPアドレスに紐づいた単一のTCPコネクションの中に存在します。そのため、ネットワークが切断されたりアドレスが変わったりすると、コネクションは死に、リモートシェルもろとも失われます。TCPはコネクションを送信元・宛先のアドレスとポートという4要素の組(four-tuple)で識別します。新しいWi-Fiネットワークから得た新しいIPは、サーバがまったく知らない新しい組を意味します。キープアライブが失敗するかソケットがエラーになると、sshdはシェルとその中のすべてのフォアグラウンドプロセスを回収します。以下の3つのツールは、この連鎖のそれぞれ異なる箇所を攻めます。

Mosh:UDP上での状態同期

障害時の挙動

Mosh は、バイトストリームモデルを状態同期に置き換えます。クライアントとサーバがそれぞれ画面のスナップショットを保持し、Moshの State Synchronization Protocol が暗号化されたUDPデータグラム上でそれらを収束させます。サーバは単に、最後に認証されたパケットの送信元アドレスに向けて送信するだけなので、IPアドレスの変更をまたぐローミングは自動的に行われます。ラップトップをスリープさせ、ネットワークを切り替えても、再接続の操作なしにセッションが再開します。予測的ローカルエコー(predictive local echo)により、サーバへのラウンドトリップを待たずに入力したキーが即座に表示されます。

必要なもの

Moshはリモートマシン上に mosh-server バイナリを必要とします(スーパーユーザ権限も常駐デーモンも不要で、両側ともあなたの権限で動作し、セッション終了とともに停止します)。加えてUDPの到達性が必要です。Moshは通常のSSHログインで認証を行い、その後デフォルトでは60000から61000の範囲のUDPポート(60001以降で最初に空いているポート)を使用するため、ファイアウォールでこれを許可する必要があります。オプションは背後のsshにそのまま渡されます。

mosh --ssh="ssh -i ~/.ssh/other_key" user@host

弱点

UDPがブロックされている場合、Moshはまったく動作しません。TCPへのフォールバックはありません。またMoshは現在画面上にある文字だけを同期するため、スクロールバックは失われます。プロジェクト自身のFAQも、リモート側でscreenやtmuxを使うよう案内しています。Eternal Terminalの両ツールの比較では、Moshがtmuxのコントロールモード(tmux -CC)を扱えないことも指摘されており、これはiTerm2ユーザーには重要な点です。プロジェクトのリリースページにおける最新バージョンは、2022年10月の1.4.0です。

Eternal Terminal:TCP上で同一セッションを継続

障害時の挙動

Eternal Terminalは、通常のTCP上で、作業中の状態(動作中のtmuxセッションを含む)を破棄せずに接続を復帰させます。そのため、回線障害のコストは作業の喪失ではなく単なる一時停止にとどまります。TCPから離れることがないため、Moshが使えないネットワーク、すなわちUDPを落とす企業ファイアウォールや、通信をTCPプロキシ経由に強制する経路でも、まさにそこで動作します。

必要なもの

Eternal Terminalはサーバ側にデーモンを必要とします。プロジェクトのREADMEは2つの前提条件を挙げています。ハンドシェイクと暗号化はsshが担うため、ETが動作する前に ssh user@hostname が動作していなければならないこと。そして、変更しない限りサーバ側はTCPポート2022で待ち受けること。インストールはmacOSでは brew install et、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以外何も必要としません。これにより、ソフトウェアをインストールできないマシンにおいて、3つの中で唯一の選択肢となります。クライアント側のインストールは次の通りです。

sudo apt install autossh   # Debian/Ubuntu
sudo dnf install autossh   # Fedora/RHEL family (may need EPEL)
brew install autossh       # macOS

弱点

復旧するのは接続であって、セッションではありません。またsshが障害を検知することに依存します。manページでは、回線が死んだ際にクライアントが速やかに諦めるよう ServerAliveIntervalServerAliveCountMax の使用が推奨されています。

その上に重ねるtmuxまたはZellij

tmuxとZellijは、これらのツールのいずれかを置き換えるものではありません。これらはサーバ上でプロセスを生かし続けるものであり、一方でMosh、Eternal Terminal、autosshはサーバへの経路を生かし続けます。この2つのレイヤーは組み合わせて使えます。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代替手段はどう選ぶべきか

次の3つを順に問いましょう。自分とサーバの間でUDPはブロックされているか。もしそうなら、Moshは除外され、耐障害性のある選択肢はEternal Terminalです。サーバに何かをインストールできるか。できないなら、autossh + tmuxが唯一の手段です。それ以外なら、好みで選びます。ローミングと悪回線での即座なエコーが欲しければMosh、本物のスクロールバックや tmux -CC が必要ならEternal Terminalです。

MoshEternal Terminalautossh
復旧モデルUDP上での状態同期、IPをまたいでローミングTCP上で同一セッションに再接続sshを再起動、新しいセッション
サーバ側の要件mosh-server バイナリ、UDPの開放root権限のデーモン、TCPポート2022sshdのみ
主な制約UDP不可の環境では使えない、セッション保持なしローカルエコーなしtmuxなしではセッションが失われる

許容できない障害モードが、使うべきツールを決めます。開放的なネットワークではまずMoshを試し、制限の厳しい環境用にEternal Terminalを用意し、そして今日のうちに autossh -M 0 と名前付きtmuxセッションをシェルのエイリアスに入れておきましょう。すでにsshできるすべてのマシンが、それだけでアップグレードされます。

FAQ

MoshはSSHの踏み台(jump host / bastion)を経由して動作しますか?

いいえ。Moshには[SSHトンネルや踏み台ホスト](https://docs.blink.sh/advanced/advanced-mosh)を扱う仕組みが組み込まれていません。踏み台ホストは最初のSSHログインを中継できますが、その後は暗号化されたUDPトラフィックが対象マシンへ直接到達しなければならず、踏み台サーバ単体ではそれを実現できません。踏み台経由のみのネットワークでは、autosshはProxyJumpをサポートする通常のsshを実行するため、そのまま動作します。

Moshは素のSSHと同程度に安全ですか?

ログインは依然としてSSH上で行われます。その後、MoshはすべてのUDPデータグラムを、認証付き暗号方式である[OCB3モードのAES-128](https://mosh.org/)で暗号化・認証します。SSHは開始時の鍵交換にのみ使われるため、SSHの脆弱性が影響するのは長時間稼働するMoshセッションではなく、この短いセットアップ段階に限られます。既存のSSH鍵とホスト検証はそのまま適用されます。

autosshは対話シェルだけでなく、SSHポートフォワードも維持できますか?

はい。永続的なトンネルはautosshの最も一般的な用途の一つです。リモートコマンドを実行しないよう -N を、監視ポートを無効化するよう -M 0 を、そして通常の -L や -R のフォワーディングフラグを付けて実行します。manページ自身の例でも、-f -M 0 -N を ServerAliveInterval と ServerAliveCountMax と組み合わせています。トンネルはシェルの状態を保持しないため、セッションが新規になるという制約は当てはまりません。autosshは単純にフォワードを再確立します。

Understand every bug

Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — self-hosted, with full data ownership.

Star on GitHub

We use cookies to improve your experience. By using our site, you accept cookies.