Mosh というソフトウェアが最近話題になっています。moshと言えばR6RS準拠のSchemeインタプリタ を連想する方も多いと思いますが、今回紹介するのは同名の別ソフトウェアです。
Moshとは、端末をリモートで操作するためのソフトウェア、簡単に言ってしまえばSSHの代替となるソフトウェアです。今週のレシピでは、SSHよりも高速で、接続のローミングができるMobile Shell、略してMoshを紹介します。
Moshのインストール
Ubuntuでは、12.04のUniverseリポジトリにMosh 1.1.3のパッケージが用意されています。また10.04、10.10、11.04、11.10の各リリースにも、backportsリポジトリにMosh 1.1.1がバックポート されています。つまりUbuntuならば、ソースビルドや野良パッケージなどに頼らずとも、Moshを簡単に使いはじめることができるというわけです。
moshパッケージには、サーバー側で動作するmosh-serverと、接続するクライアントであるmosh-clientの両方が含まれています。opensshはサーバーとクライアントが別パッケージになっていましたが、moshの場合はサーバーとクライアント双方に、同じmoshパッケージをインストールすることになります。
図1 10.04~11.10までの場合は、Backportsを有効にする
moshパッケージのインストール
$ sudo apt-get install mosh
Moshのしくみ
前述の通り、Moshはクライアントであるmosh-clientと、サーバーであるmosh-serverで構成されるソフトウェアです。まずmosh-serverですが、これはデーモンとして常時起動しているプログラムではありません。mosh-serverコマンドを実行すると、mosh-serverは今回限りの接続用のキー[1] と、待ち受けるUDPのポートを標準出力に表示し、それから一定時間(60秒)だけこのポートでクライアントの接続を待ちます。ユーザーはmosh-serverが生成したキーをクライアントの環境変数「MOSH_KEY」に設定した上で、mosh-clientを使用してこのポートに接続を行なう必要があります。なお接続が行なわれなかった場合は、60秒後にmosh-serverは自動的に終了します。
mosh-serverの実行例
(server)$ mosh-server
MOSH CONNECT 60001 Vec7hQHkpn9bVFfM92A42Q
mosh-server (mosh 1.1.3)
Copyright 2012 Keith Winstein <mosh-devel@mit.edu>
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
[mosh-server detached, pid = 3184]
mosh-serverがUDPのポートを待ち受けていることを確認
(server)$ sudo netstat -uap
稼働中のインターネット接続 (サーバと確立)
Proto 受信-Q 送信-Q 内部アドレス 外部アドレス 状態 PID/Program name
udp 0 0 *:60001 *:* 3184/mosh-server
mosh-clientから接続する
(client)$ MOSH_KEY=DfFLaXW8vwWXjlO47gnyXg mosh-client www.example.com 60001
図2 60秒以内にクライアントが接続してこなかった場合、mosh-serverは停止する
moshコマンドでサーバーに接続する
Moshでの接続手順は以下のようになっています。
サーバーにSSHで接続する
mosh-serverを起動する
ポート番号とキーをメモする
クライアントに環境変数MOSH_KEYを設定する
mosh-clientからサーバーに接続する
上記のとおり、Moshでサーバーに接続するためには、まずSSHで接続してサーバーを起動しなければなりません。この非常に面倒な作業を引き受けてくれるのが、moshパッケージに同梱されているmoshコマンドです。moshコマンドはPerlで書かれたフロントエンドで、内部で一旦ssh接続を行ない、mosh-serverを起動して鍵とポート番号を取得し、クライアントにKEYを設定してmosh-clientを起動する、という一連の処理を自動的に行なってくれます。そのためユーザーは、sshコマンドと同じノリでmoshコマンドを叩くだけでmoshを利用することができます。ちなみに、mosh実行時に"mosh requires a UTF-8 locale."というエラーが出る場合があります。この場合は環境変数LC_CTYPEにen_US.UTF-8を設定してから、moshを実行してください。
このようにMoshはサーバーの起動や認証をSSHに依存しています。そのためMoshサーバーは、SSHサーバーとしてもセットアップしておく必要があります。MoshはSSHの代替として使えるソフトウェアですが、SSHを完全に置き替えることができるソフトウェアではありません。
moshコマンドの例
(client)$ mosh example.com
ロケールが異なる場合
(client)$ mosh www.example.com
mosh requires a UTF-8 locale.
Connection to www.example.com closed.
/usr/bin/mosh: Did not find mosh server startup message.
(client)$ LC_CTYPE=en_US.UTF-8 mosh www.example.com
ファイヤーウォールの設定
本連載76回 で紹介したように、UbuntuにはUFWというファイヤーウォール設定ツールが用意されています。VPSなどでは、UFWを利用してファイヤーウォールを設定している読者の方も多いでしょう。MoshはUDPの60000~61000番ポートを利用しますので、もしもファイヤーウォールを設定しているならば、事前にこのポートを開放しておきましょう。
また筆者はAmazon EC2でUbuntu Serverを運用しています。Amazon EC2の場合は、仮想サーバーで使用しているセキュリティグループに「Custom UDP rule」として60000-61000を追加しておけば問題ありません。
UFWでMosh用のポートを開放する
(server)$ sudo ufw allow 60000:61000/udp
(server)$ sudo ufw status
Status: active
To Action From
-- ------ ----
22 LIMIT Anywhere
60000:61000/udp ALLOW Anywhere
60000:61000/udp ALLOW Anywhere (v6)
図3 Amazon EC2のセキュリティグループに変更を入れる
ユーザー権限でのインストール
mosh-serverは「SSHでログインしたユーザーが起動するプログラム」なので、一般ユーザー権限で任意の場所へインストールしてもかまいません。例えばGitHubから最新のMoshのソースコードを取得し、自分のホームディレクトリにインストールしてみる、などが可能です[2] 。
Moshのビルドとホームディレクトリへのインストール
$ git clone https://github.com/keithw/mosh ~/src/mosh
$ cd src/mosh
$ ./autogen.sh
$ ./configure --prefix=/home/ubuntu/mosh
$ make
$ make install
この例のように通常と異なるパスへインストールした場合、moshコマンドがmosh-serverを見つけることができなくなります。そのような場合は、moshコマンドの--serverオプションで、mosh-serverのパスを指定して起動してください。
mosh-serverを指定して接続する
(client)$ mosh example.com --server /home/ubuntu/mosh/bin/mosh-server
サーバーによってはファイヤーウォールの都合などで、60000-61000番のポートが使用できないこともあるかもしれません。その場合は-pオプションでmosh-serverが待ち受けるポートを指定することも可能です。
mosh-serverが待ち受けるポートを指定する
(client)$ mosh example.com -p 50000
[2] もちろん依存するパッケージが導入済みである必要はあります。Moshのビルドには、protobuf-compiler、libprotobuf-dev、libboost-dev、libutempter-dev、libncurses5-dev、zlib1g-devなどのパッケージが必要で、moshコマンドの実行にはlibio-pty-perlが必要です。
Moshの特徴
Moshには「ローミングができる」「 接続が切れても平気」「 高速なローカルエコー」といった特徴があります。
SSHをモバイル環境などで使っていると、電波状況などによっては通信が不安定になり、セッションが切れてしまうことがあります。セッションが切れるとリモートで実行中のプログラムも終了してしまうため、SSH使用時はサーバー上でGNU screenなどを使って、回線切断によるプログラムの強制終了に備えるのが一般的です。screenを使っておけば仮にセッションが切れたとしても、再度接続してアタッチしなおすことで、実行中のプログラムに復帰することができるからです。
対してMoshでは、mosh-serverがscreenと同じように働きます。mosh-server上でシェルが実行され、mosh-serverが終了するまで(つまりクライアントがexitするまで) 、その上で走っているプログラムはクライアントの状態とは関係なく実行され続けます。
MoshはUDPで通信を行なうため、セッションが切れるどころか、そもそもセッションという概念がありません。たとえば外出先で3G回線からMosh接続を行ない、そのままノートPCの蓋を閉じてスリープさせたとします。しかし帰宅後に自宅のLANにPCを繋げば、自動的にサーバーとの通信が再開されます。クライアントのIPアドレスが変更されても問題ありません。
またMoshは入力した文字をローカルエコーするため、遅いネットワークを使っていてもキー入力時に「待たされる」ことがありません。
図6 プロセスツリーの例。mosh-server上でシェルが実行されている
図4 3Gモバイル接続中にネットワークを切ると、このような表示が出る
図5 自宅のWiFiに再接続したところ。問題なく作業に復帰することができる
こういったローミングやローカルエコーというMoshの特徴は、State Synchronization Protocol(SSP)と呼ばれる、UDP上に構築された新しいプロトコルによって実現されています。つまりMoshは単なる新しいシェルというよりも、SSPを利用したはじめてのアプリケーション実装と言うほうが正しいでしょう。
Moshはクライアントとサーバーの両方で、個別に画面のスナップショットを維持しており、それをSSPによって同期することによって動作しています。従来のSSHでは、すべてのバイトストリームを順番に流す必要がありました。しかしMoshは、効率よく最新の状態と同期するように動作します。具体的には、画面の中間フレームをスキップして、最新の状態と同期することが可能です。つまり回線に無駄な負荷をかけません。
たとえばSSHで細い回線に重いデータを流してしまうと、「 Ctrl+Cを連打してもなかなか止まってくれない」という状況は、誰でも経験があるのではないでしょうか。Moshならば、そんな状態でも即座にCtrl+Cでプログラムを停止することができます。SSPはサーバーから送信されたすべてのデータを受信する必要がないため、同期の速度を制御することができるからです。SSPはネットワークバッファがあふれないようフレームレートを調整し、快適な応答性を確保しています。
おわりに
筆者は複数のサーバーを相手に作業することが多いので、常々手元のGnome端末でByobuを使いたいと思っています。しかしSSHを使うと前述のように、サーバー上でもscreenを使う必要が出てきます。さらに筆者はscreenをネストさせたくないので、仕方なくクライアントではByobuを使わず、ターミナルを複数起動するという運用をしていました。しかしこれからは、手元のByobuの上で複数のmosh-clientを起動するという、すっきりした運用ができそうです。
モバイル環境でSSHを使う人や、あっちこっち移動しながら作業するような人は、Moshを試してみてはいかがでしょうか。