SSHトンネルを確実にオープンに保つには?
私は職場のSSHトンネルを使って、いろいろなアイドックなファイアウォールを迂回しています(上司には問題ないのですが…)。問題は、しばらくすると ssh 接続がハングアップしてしまい、トンネルが壊れてしまうことです。
せめてトンネルを自動的に監視できれば、ハングアップしたときにトンネルを再起動できるのですが、その方法すら思いつきませんでした。
もちろん、ssh 接続がハングアップしないようにする方法を教えてくれる人にはボーナスポイントをあげよう!
私は職場のSSHトンネルを使って、いろいろなアイドックなファイアウォールを迂回しています(上司には問題ないのですが…)。問題は、しばらくすると ssh 接続がハングアップしてしまい、トンネルが壊れてしまうことです。
せめてトンネルを自動的に監視できれば、ハングアップしたときにトンネルを再起動できるのですが、その方法すら思いつきませんでした。
もちろん、ssh 接続がハングアップしないようにする方法を教えてくれる人にはボーナスポイントをあげよう!
autossh ](http://www.harding.motd.ca/autossh/) が必要なようです。これは ssh トンネルを監視し、必要に応じて再起動します。私たちは数年前からこれを使用していますが、うまく機能しているようです。
autossh -M 20000 -f -N your_public_server -R 1234:localhost:22 -C
-Mパラメータの詳細は こちら です。
すべてのステートフルファイアウォールは、しばらくの間その接続のパケットを見ないと、接続を忘れてしまいます(接続を閉じずに両端が死亡した接続でステートテーブルがいっぱいになるのを防ぐため)。ほとんどのTCP実装では、相手側からの連絡がないまま長い時間が経過した後にキープアライブパケットを送信します(2時間が一般的な値です)。しかし、キープアライブパケットを送信する前に接続を忘れてしまうステートフルファイアウォールがある場合、長持ちするがアイドル状態の接続は死んでしまう。
もしそうなら、解決策は接続がアイドル状態にならないようにすることです。OpenSSH には ServerAliveInterval というオプションがあり、これを使って接続が長くアイドル状態になるのを防ぐことができます (おまけとして、接続がアイドル状態になっていても、相手がいつ死んだかをすぐに検出してくれます)。
あなた自身のmacまたはlinuxマシンで、3分ごとにサーバのsshを生きた状態に保つようにsshを設定します。ターミナルを開いて、自宅の見えない .ssh に移動します。
cd ~/.ssh/
に移動し、1行の設定ファイルを作成します。
これには Systemd が理想的です。
[Unit]
Description=SSH Tunnel
After=network.target
[Service]
Restart=always
RestartSec=20
User=sshtunnel
ExecStart=/bin/ssh -NT -o ServerAliveInterval=60 -L 5900:localhost:5900 user@otherserver
[Install]
WantedBy=multi-user.target
(ssh コマンドを適宜変更してください)
/etc/systemd/system/sshtunnel.service
として実行されるので、最初にユーザが存在することを確認してください sshtunnel
を発行して起動時に起動するように設定してください systemctl enable sshtunnel
を発行して直ちに起動してください Update Jan 2018 : いくつかのディストリビューション (例: Fedora 27) は SELinux のポリシーを使用して、systemd init で SSH を使用できないようにしている場合があります。 その場合、必要な除外を提供するためにカスタムポリシーを作成する必要があります。
ServerAliveCountMaxを誤解しているように見えます。ドキュメントを理解している限りでは、これは接続を終了させずに応答しないことができるサーバーアライブメッセージの数です。ですから、ここで議論しているようなケースでは、これを高い値に設定することは、ハングした接続が検出されずに終了されないことを保証するだけです!
ServerAliveIntervalを設定するだけで、ファイアウォールが接続を忘れてしまう問題を解決するのに十分なはずです。
あなたが望むのは、1) 通常の状況下では接続が永続的に開かれたままであること、2) 接続の失敗を検出し、失敗時に発信側が終了すること、3) ssh コマンドが終了するたびに再発行されることです (どのようにするかは非常にプラットフォームに依存します。Jawa が提案した “while true” スクリプトは一つの方法です。)
期限切れのNATセッションによってトンネルの問題が発生した場合には、常にServerAliveInterval
SSHオプションを使用してください。
接続性が完全にダウンした場合には、常にレスパワード方法を使用してください。
bash スクリプト (while true do ssh ...; sleep 5; done
) sleep コマンドを削除しないでください。
ssh
が利用できないUbuntu上のアップスタートスクリプト。
/etc/inittab
が利用できないUbuntu上でのアップスタートスクリプト。
この問題はこれで解決しました。
~/.ssh/config
を編集して、
ServerAliveInterval 15
ServerAliveCountMax 4
を追加しました。
ServerAliveCountMax
Sets the number of server alive messages (see below) which may be
sent without ssh(1) receiving any messages back from the server.
If this threshold is reached while server alive messages are
being sent, ssh will disconnect from the server, terminating the
session. It is important to note that the use of server alive
messages is very different from TCPKeepAlive (below). The server
alive messages are sent through the encrypted channel and there‐
fore will not be spoofable. The TCP keepalive option enabled by
TCPKeepAlive is spoofable. The server alive mechanism is valu‐
able when the client or server depend on knowing when a connec‐
tion has become inactive.
The default value is 3. If, for example, ServerAliveInterval
(see below) is set to 15 and ServerAliveCountMax is left at the
default, if the server becomes unresponsive, ssh will disconnect
after approximately 45 seconds. This option applies to protocol
version 2 only.
ServerAliveInterval
Sets a timeout interval in seconds after which if no data has
been received from the server, ssh(1) will send a message through
the encrypted channel to request a response from the server. The
default is 0, indicating that these messages will not be sent to
the server. This option applies to protocol version 2 only.
ExitOnForwardFailure yes
は他の提案の良い補助手段です。接続してもポート転送を確立できない場合は、接続していないのと同じように役に立たない。
最近、私自身もこの問題を抱えていました。これらのソリューションでは、パスワードログインを使用する場合、毎回パスワードを再入力する必要があるため、バッチファイルにパスワードが保存されないように、テキストプロンプトと一緒に sshpass をループで使用しました。
同じ問題を抱えている人がいる場合に備えて、この問題に関する私の解決策を共有しようと思いました:
#!/bin/bash
read -s -p "Password: " pass
while true
do
sshpass -p "$pass" ssh user@address -p port
sleep 1
done
autossh
はニーズを満たしていないので(最初の試みでサーバに接続できないとエラーで存在する)、純粋なbashアプリケーションを書きました。 https://github.com/aktos-io/link-with-server
これはデフォルトでサーバ上のNODEのsshdポート(22)のための逆トンネルを作成します。他のアクション(追加ポートの転送、接続時のメール送信など)を行う必要がある場合は、スクリプトをon-connect
とon-disconnect
のフォルダに配置することができます。
私は以前使っていたISPで同じような問題を抱えていました。私の場合は、どのTCP接続でも、ウェブサイトを訪問したり、メールを送信したりしても同じでした。
解決策は、UDP上でVPN接続を設定することでした(私はOpenVPNを使用していました)。この接続は、切断の原因が何であれ、より耐性がありました。これで、この接続を介してあらゆるサービスを実行できるようになりました。
接続にはまだ問題があるかもしれませんが、トンネルがより寛容になるので、どの ssh セッションでも切断されるのではなく、短い保留時間を感じることができます。
これを行うには、自分のサーバで設定できるオンラインの VPN サービスが必要です。