動的IPアドレスのクライアントにsshトンネリングを維持させる方法です。思いのほか苦労したので記録しておきます。ちなみにcygwinのautosshを使用しています。
1. sshd側でClientAliveIntervalを設定する
これを設定しないとネットワーク切断後にもsshdのプロセスが永久に残り続けるという恐ろしい事態が発生します。sshdのプロセスが残っているとトンネルしたいポートが占有され続けて、トンネルを再開できなくなります。
sshdはClientAliveInterval
の間隔(秒)でクライアントに対して応答確認を行い、失敗したらsshクライアントを切断します。
この非常に重要なClientAliveInterval
はGentooではデフォルト値が設定されているようですが、Ubuntuでは設定されていないようです。
ClientAliveInterval 15
ClientAliveCountMax 3
sshd_config
を編集したらsshdを再起動して設定を反映させる必要があります。
ebizou-rion.hatenadiary.org
2. autosshの-M
オプションで通信監視ポートを固定する
autosshの-M
オプションで通信監視ポートを必ず固定する必要があります。このポートには使用されていない適当なポートを指定します。トンネルしたいポートを指定してはダメです。
この設定により、ネットワーク切断後、上記1.の設定によりsshdのプロセスが終了されて通信監視ポートが解放されるまでautosshは接続をリトライし続けます。つまり、autossh接続は排他制御されて、同時に存在するautossh接続は1つだけになります。
この設定をしないと、sshdのプロセスがサーバーにまだ残っている段階でautosshがssh接続を再開してしまいます。そうするとssh接続は再開するものの、まだ残ってる古いsshdプロセスがトンネルしたいポートを占有しているので、トンネリングを再開させることができません。
なお、ちょっと設定は不明ですが、素のOpenSSHクライアントでもトンネリングに失敗した時ssh接続を切断するというに設定にもできるようなので、それで排他制御することも可能かもしれません。ここでは-M
オプションで排他制御しました。
ちなみに-M
オプションを使用しないと空いているポートが通信監視に使用されるためautossh接続の排他制御になりません。-M 0
にすると通信が監視されません。これらの設定にしてはいけません。
3. その他必須ではないが必要かもしれない設定
3.1. autosshのポーリング間隔を設定する
autosshのポーリング間隔はデフォルトで600秒です。これは長すぎる気がするので短くしました。オプションではなく環境変数で設定します。
AUTOSSH_POLL=15
3.2. ExitOnForwardFailure
は設定しない
ExitOnForwardFailure
がYes
になっていると、ポートフォワードが失敗した時にautosshも終了してしまいます。ExitOnForwardFailure
が設定されてないか~/.ssh/config
の記述を確認しましょう。
3.3. autosshにハートビートさせる
上記1.で設定したClientAliveInterval
はsshd側のハートビート設定で、クライアント側のハートビート設定がServerAliveInterval
になります。タイムアウトさせないためにはどちらか片方だけ設定すれば十分なので、別に設定しなくていいですが、両方設定しても問題はないです。クライアントにもハートビートさせたい場合はどうぞ。
-o ServerAliveInterval=15 -o ServerAliveCountMax=3
ssh 接続をタイムアウトしないようにする · GitHub
以上まとめると最終的なコマンドは以下のようになります。
AUTOSSH_POLL=15 autossh -vvv -M 54321 -i 証明書のパス -L 12345:127.0.0.1:12345 -R 8080:127.0.0.1:8080 ホスト名
-vvv
は冗長なログを表示するオプションです。
localhost
ではなく127.0.0.1
を使用しているのは私のcygwin環境だとlocalhost
が解決できないためです。
所感
以上のとおりautosshのオプションとsshの設定が調和して初めてトンネルを維持できるようになっており、非常にややこしいです。