Mosh 徹底解説(インストール方法、メリット、仕組み)

ターミナル画面のイメージ画像

Mosh(Mobile Shell)は、SSHに代わってリモートマシンと接続するために開発されたアプリケーションです。

主な特徴として、モバイル回線やフリーWi-Fi等の不安定な通信環境下でも快適に動作するという点が挙げられます。サーバーとの通信が切断されても自動で復帰してくれるという機能も備わっています。

今回は、Moshの仕組み、メリットと、利用方法についてまとめてみました。

Moshとは?

Moshは、通信の安定性が低く、遅延の多いようなモバイル環境でも快適にリモートマシンと接続することができるように開発されたアプリケーションです。

SSHとほぼ同じ使用感で使うことができます。クライアント認証はSSHを使って行われるので、パスワードや公開鍵などの接続情報をそのまま使えるという利点がありますが、SSHを完全に置き換えることはできません。

詳細な仕組みは、設計・動作の詳細を参照。

Moshを使うメリット

導入にあたって、複雑な作業や設定が不要

先述したように、パスワードや公開鍵などの接続情報はSSHで使っているものをそのまま流用することができ、基本的にサーバ側での対応作業はMoshのインストールとファイアウォールの許可設定だけで済むので、簡単に導入することができます。

クライアントのIPアドレスが変わっても接続が維持される

IPアドレスがコロコロ変わるような環境では有効です。

ネットワーク接続が切断されても、接続再開後に自動で復帰

ノートPCでSSHを使っていて、スリープモードになったり別のアクセスポイントに接続したりして、コネクションが切断されるという経験がある方も多いかと思います。

Moshでは、接続の再開を自動で行ってくれるので、回線の状態を意識する必要がありません

改善されたローカルエコー

ローカルエコーとは、入力したコマンド文字列をターミナル画面に表示する機能のことです。SSHのローカルエコーはサーバ側の応答を待って行われるため、遅延やパケットロスの大きい通信環境では文字を入力してから、それが画面上に表示されるまでタイムラグが生じます。

Moshはバックグラウンドで予測モデルを実行し、入力をローカルエコーするべき(多くの入力がこれに当たる)か、しないべきか(パスワード文字列などは表示されるべきでない)を予測します。前述したような低品質な通信環境では、サーバからの応答を待たず、この予測をもとにローカルエコーを行うことで、ユーザーエクスペリエンスを向上させます。

セキュリティリスクの低さ

Moshは、root権限を必要とせず、デーモンとして常駐することもないので、無用なセキュリティリスクを負うことが少なくなります。

利用方法(サーバ側)

CentOS での導入方法を解説します。

CentOS 以外のインストール方法は、https://mosh.org/ の Getting Mosh を参照。

インストール

yumからインストールするには、EPELリポジトリの追加が必要になります。

#EPELが追加されていない場合
$ yum install epel-release

$ yum install mosh

ファイアウォールの設定

MoshはUDPの60000~61000番ポートを使用するので、ファイアウォールの許可設定をします。

ちなみに、上記ポートを全て開放する必要はなく、60000番から、同時接続する分+1ポート※1Mosh公式サイトでは、60000番ポートも使用しているような記述がされていますが、実際接続に使われるのは60001番ポートからになります。60000番ポートが何に使われるのか、そもそも使われているのかどうかは不明です。だけポートを開放しておけば問題なく動作します。

例えば、同時10接続まで許容する場合は、60000~60010番ポートへの接続を許可します。

firewalldの場合

firewalldを使用している場合の設定方法です。

Moshはすでにサービスとして登録されているので、60000~61000番ポートを開放してよい場合は以下の設定のみでOKです。

$ firewall-cmd --permanent --add-service=mosh
$ firewall-cmd --reload

一部のポートのみ開放する場合は、合わせて以下の設定が必要です。

$ firewall-cmd --permanent --service=mosh --remove-port=60000-61000/udp

#許可したいポートレンジを指定(この例では60000~60010番ポート)
$ firewall-cmd --permanent --service=mosh --add-port=60000-60010/udp

$ firewall-cmd --reload

iptablesの場合

iptablesを使用している場合の設定方法です。

一部のポートのみ開放する場合は、適宜ポートの指定を変更してください。

#以下のエントリをiptablesに追加する
-A INPUT -p udp -m udp --dport 60000:61000 -j ACCEPT

#iptablesを再起動して設定を反映させる
$ systemctl restart iptables

利用方法(クライアント側)

Windows

MobaXtermというターミナルアプリケーションを使うと簡単にMoshが利用できます。

以下のリンクからダウンロード可能です。

https://mobaxterm.mobatek.net/download.html>

HomeEdition(無料)で大丈夫です。インストーラー版とポータブル版を選べますが、どちらでも構いません。

起動したら、画像の①→②の順でクリックし、接続情報を設定します。接続情報は、SSHと同じものを使います。

MobaXterm のMosh接続設定画面

iOS

Termius というアプリ(無料)からMoshを使うことができます。

以下のリンクからダウンロード可能です。

App Store からダウンロード

(1)起動し、HostsからNew Hostを選択

Termius の Hosts画面

(2)以下の画像のようにして接続情報を設定する

Termius の接続設定画面(3)Moshを使って接続できる

Termius のターミナル画面

設計・動作の詳細

最後に、Moshの仕組みについてまとめてみました。普通に使う分には不要な情報なので、スルーしてもらっても構いません。

概要

Moshは、UDP上でSSP(State Synchronization Protocol)というプロトコルを介してクライアント・サーバ間を接続します。

SSPは、ローカルノード間での状態同期を行うことを目的としています。SSPはクライアント・サーバ間の双方向に接続され、クライアントからサーバへはユーザーの入力を、サーバからクライアントへはターミナルウィンドウの内容を転送します。

Moshのセッションを開始するには、ユーザーがSSH等を介して接続し、サーバ側のMoshを起動します。MoshはデフォルトでUDPの60001番ポートから60999番ポートのうち最初に使用可能なポートをリッスンし、接続は128ビットのAES-OCB (OCB3)で暗号化されます。その後、SSH接続は切断され、UDPを介してサーバとの通信が開始されます。

SSP(State Synchronization Protocol)

SSPは、2つのレイヤーに分けることができ、データグラム層トランスポート層が存在します。

データグラム層は、1.ローミング接続の維持 と 2.リンクのタイミングの制御 を行います。

1.ローミング接続の維持とは、IPアドレスが変わったり、接続が切断されたりなど、ネットワーク接続が変更されてもコネクションが維持されることを意味します。

これを可能にするために、SSPではパケットにシーケンス番号(パケットを識別する一連の番号のこと。送信するたびに加算されていく。)を付加しています。クライアントから送信される最新のパケット(シーケンス番号が最大のもの)には、その時点での送信元IPアドレスやポート番号等の情報が含まれているので、サーバー側がクライアントのIPアドレスの変更を検知することができ、セッションを自動で継続することができます。

また、クライアント・サーバは3秒ごとにハートビートパケットを送信するので、ターミナルを操作していなくともローミングは機能します。

2.リンクのタイミング制御は、SRTTとRTTVAR※2どちらもRTTの移動平均の一種。TCPでも、再送タイムアウト時間(RTO)を設定するのに使われている。ちなみに、SSPにおける再送タイムアウト時間の下限は50ミリ秒に設定されており、TCPと比較して迅速にパケットロスを検出できるという。を推定することによって行います。

このため、SSPでは、すべての発信パケットにミリ秒単位のタイムスタンプと、リモートホストから受信した最新のタイムスタンプである、「応答タイムスタンプ」が付加されます。これにより変動するRTTを継続的に予測することができます。

予測されたRTTは、再送タイムアウトを設定するのに使われるほか、送信するパケットの間隔(フレームレート)を調整し、ネットワークバッファがいっぱいになることを防ぎます。これにより、Control-Cなどの割り込みが常に機能します。

ここまでの説明を聞いてお気づきの方もいるかもしれませんが、MoshではUDPとSSPによって、TCPのうち必要な一部機能を実装しつつ、さらに独自の機能を実装しています。

トランスポート層は、ローカルノードの状態をリモートホストに同期させる役割を担います。

送信側は、送信側と受信側の状態と、それらの差(diff)を送信することによって、受信側を同期させます。このdiffは、ユーザー入力を同期する場合はそのキーストロークが含まれ、画面状態を同期する場合にはクライアントのフレームを現在のフレームに変換するための最小のメッセージとなります。

投機的ローカルエコー

Moshはサーバとクライアント双方の画面状態を保持しています。これにより、ユーザーのキー入力に対する画面状態の変化について予測を行い、のちにサーバから送られてくる画面状態と予測を比較することで予測を検証することができます。Moshはこれを利用して、高遅延やパケットロスが多いネットワーク上でのユーザーエクスペリエンスを向上させます。

具体的には、ローカルエコーが改善されます。Moshはバックグラウンドで予測モデルを実行し、ユーザーの入力を即座にエコーするべきか、しないべきかを予測します。そして、特定の条件下でこの予測に従い、サーバーからの応答を待たずにローカルエコーを表示します。これは前述したような低品質なネットワーク環境にある場合のみ行われます。

パフォーマンス

SSHとMoshのパフォーマンスを比較します。6人のユーザーから提供された、約1万回のキーストロークが含まれたトレースを、3Gネットワークを介して再現し、応答時間を計測した結果が下図です。(K. Winstein and H. Balakrishnan, 2012 より抜粋)

SSH と Mosh のキーストロークに対するレスポンス時間の比較結果Moshが投機的ローカルエコーを表示できるとき、キーストロークに対する応答はほぼ瞬時に行われており、これは全体の約70%を占めていました。投機的ローカルエコーが表示できない場合では、応答時間はSSHのものと似た傾向を持つことがわかりました。

また、全体の0.9%のキーストロークに対して誤った予測が行われ、RTTの範囲内で訂正されました。

参考

Mosh: An Interactive Remote Shell for Mobile Clients

脚注   [ + ]

1. Mosh公式サイトでは、60000番ポートも使用しているような記述がされていますが、実際接続に使われるのは60001番ポートからになります。60000番ポートが何に使われるのか、そもそも使われているのかどうかは不明です。
2. どちらもRTTの移動平均の一種。TCPでも、再送タイムアウト時間(RTO)を設定するのに使われている。ちなみに、SSPにおける再送タイムアウト時間の下限は50ミリ秒に設定されており、TCPと比較して迅速にパケットロスを検出できるという。

あわせて読みたい

コメントを残す

質問・感想などお気軽にどうぞ。
*が付いている項目は入力必須です。メールアドレス以外の項目が公開されます。
スパム防止のため、コメント反映まで少々時間がかかります。