ssh -X で X Window の PortForwarding

ssh -X を使うと、リモートサーバ上で動いている X クライアントの画面をローカルで動いている X サーバに表示できる。

X クライアント(=X Window アプリケーション)は、DISPLAY 環境変数を参照して表示先(X サーバ)を特定する。DISPLAY=192.168.0.1:3.0 となっていたら、192.168.0.1 の ポート 6000 + 3 = 6003 で待機している X サーバのスクリーン0 という意味だ。ローカルで表示する場合は DISPLAY=:0.0 のようになっている。

ssh -X はポートフォワーディングによって X Window の通信をトンネルする。ssh -X の接続先(リモートサーバ)では sshd が 6000 以降の開いているポートを適当に探し、接続待機する。この動作はリモート上で netstat -l とすれば確認できる。例えば、6013 が開いていたとしよう。するとリモート上で DISPLAY=:13.0 が自動的に設定される。リモートサーバ上で起動した X クライアントは、これを参照して、リモートサーバのポート 6013 に接続する。sshd は、このポートへの接続をローカル(ssh クライアント)へ転送し、ssh クライアントは自身の DISPLAY 環境変数を参照して、クライアントが起動された環境での X サーバに転送する。こうしてトンネルが完成する。つまり、サーバ上で動く X クライアントは、ssh クライアントの動いている PC に直接接続しているわけではない。ssh -X (や -Y) の結果、サーバ上で DISPLAY 変数がローカルホストになっているのは正常な動作なのである。

この説明で分かったと思うが、ssh -X で接続を張るたびにサーバ上でのトンネル入り口は作り直される。サーバ上で screen を動かしてセッションを持続させることがあると思うが、X Window アプリケーションの接続までは維持できない(Connection lost で死んでしまう)ので注意が必要である。また、X window アプリケーションを再起動するにせよ、screen の内部の環境変数は外側が変わっても変化しないので、トンネル入り口ポートが変わった場合は DISPLAY 環境変数を手動で設定しなおす必要がある。

なお、X window のセッションを維持するには、xmove や xpra などがあるらしい。