SSH の接続を生かすための助言の多くは「ServerAliveInterval 30 を追加しよう」で止まり、役に立つ部分を置き去りにしています。キーワードはクライアント側のタイマーで、チャネルが静かだったときだけ発火し、秒数ではなく未応答のプローブを数え、最初に一致した値が勝つファイルの中に住んでいます。この三つの性質を取り違えると、健全な VPN セッションはそれでも切れ、死んだセッションはぶら下がったままになります。

二つの方向は別々のデーモンに属する

ServerAliveInterval を読むのはあなたの ssh クライアントです。ClientAliveInterval を読むのは遠い側の sshd で、逆方向に、サーバーからクライアントへプローブします。両者は別名でもなければ協力もせず、片方を設定してももう一方の端の挙動には影響しません。両者を取り違えるのが、あるホストでは修正が効いて次のホストでは効かない、というよくある原因です。

どちらもゼロを受け付けます。ゼロではクライアントは何も送らず、サーバー側では ClientAliveCountMax がゼロだと、未応答の検査のあとに続くはずの切断が無効になります。

プローブが証明することと、しないこと

設定した間隔が過ぎてもサーバーからデータが届かないとき、クライアントは既存の暗号化チャネルを通して小さな要求を送り、返答を待ちます。ServerAliveCountMax は、セッションが切られる前に未応答のまま許される数を決めます。間隔 60 と回数 3 なら、クライアントはおよそ三分の沈黙で諦めますが、この数字はネットワーク標準ではなくあなたの設定の性質です。間隔を既定値の 0 のままにするとプローブは一切送られず、だからこそ標準的なクライアントは死んだ接続の上にいつまでも座っていられます。

やり取りは SSH トランスポートの中で行われるため、返答は相手の SSH プロセスがまだ読み書きしていることを証明します。そのセッションの中で起動したプログラムについては何も語りません:データベースクライアント、転送したポート、長時間動くスクリプトは、トランスポートが平然とプローブに答えている間に固まっていることがあります。

TCPKeepAlive は一つ下の層にある別の仕組みです。カーネルが扱い、暗号化はされず、SSH デーモンが固まった相手でもこれを満たせます。だからこそ、ソケットではなくセッションを気にするなら、SSH レベルのプローブのほうが意味のある信号です。

どちらの値が生き残るかは順序が決める

OpenSSH は各パラメーターについて最初に得た値を適用するので、特定の Host ブロックは、同じく一致するより広いブロックより前に現れなければなりません。ワイルドカードの既定値はファイルの先頭ではなく末尾に置き、さらに下の Match ブロックはすでに設定された値を上書きできないことを覚えておいてください。OpenSSH クライアント設定のリファレンスは最初の値の規則を直接述べており、共有設定を組み替える前に一度読む価値があります。

コマンドラインのオプションはファイルに勝つので、一時的な実験は安く済みます:

ssh -o ServerAliveInterval=15 -o ServerAliveCountMax=4 office-shell

思い込んでいる記述ではなくクライアントが実際に解決した内容を見るには、有効な設定を出力させてください。出力にはそのホスト名に対するマージ後の値が入っており、紛れ込んだ前のブロックを見つける最短の方法です:

ssh -G office-shell | grep -i alive

トンネルの上で keepalive がすること

定期的な通信は、状態を持つ NAT やファイアウォールのマッピングが期限切れになるのを防ぎ、これは、数分後にアイドル状態のフローを落とすゲートウェイを持つ VPN では実際の利点です。60 秒ごとに届くプローブは、アプリケーションのデータを一切運ばずにそのマッピングを更新します。

消えた経路を組み直すことはできません。トンネルのインターフェースが消えるとプローブも他のすべてと同じように失敗し、回数を使い切った時点でセッションは終わります。生存の検出と経路の回復は別の問題で、ssh_config で設定できるのは前者だけです。間隔と回数が実際に買ってくれるのは、クライアントがどれだけ早く気づくかであり、利用者がそれを固まることとして体験する部分です。

多重化された接続はしわを一つ加えます。ControlMaster が関わるとプローブはマスター接続に属し、既存のマスターの上の新しいセッションはそのマスターが交渉したものを引き継ぎます。mux のマスターが固まっていれば、別のウィンドウを開いても経路を再び試すことにはなりません。

設定を最初から最後まで確認する

サーバーでは、ファイルを読んでどの include が勝ったかを推測するのではなく、デーモンの有効な設定を出力してください:

sshd -T | grep -i clientalive

そのうえでデバッグ出力を有効にした実際のセッションを観察します。回数を使い切るとクライアントはタイムアウトの行を出し、その前後のタイムスタンプが、沈黙が続いたのかプローブが一度も送られなかったのかを示します。プローブの通信なしに死ぬセッションは、たいてい一度も一致しなかったブロックにキーワードを持っています。

トンネル経由でしか届かないホストには、二つの確認を足す価値があります:解決された間隔が意図したものかどうか、そしてその間隔に回数を掛けたものが VPN ゲートウェイのアイドルタイムアウトより短いかどうかです。後者の数が大きいと、ゲートウェイが先に静かにフローを落とし、SSH のプローブは何かを報告する機会を得られません。

関連記事