web-dev-qa-db-ja.com

SSHリモートポート転送に失敗しました

フォローアップ:数か月ごとに各サーバーを実行すると同時に発生する一連の切断が急速に発生するのは偶然の一致であり、実際の問題を明らかにするのに役立っているようです。再接続に失敗した理由は、ほぼ確実にAliveInterval値(kasperdの回答)によるものです。 ExitOnForwardFailureオプションを使用すると、再接続する前にタイムアウトが適切に発生し、ほとんどの場合問題が解決されます。 MadHatterの提案(killスクリプト)は、他のすべてが失敗した場合でもトンネルが再接続できるようにするためのおそらく最良の方法です。

ファイアウォールの背後にサーバー(A)があり、小さなDigitalOcean VPS(B)へのいくつかのポートでリバーストンネルを開始するため、BのIPアドレスを介してAに接続できます。トンネルは約3か月間一貫して動作していますが、過去24時間に4回突然失敗しました。同じことが別のVPSプロバイダーでしばらく前に起こりました-数ヶ月の完全な動作、そして突然複数の急速な障害。

マシンAに、トンネルコマンド(ssh -R *:X:localhost:X address_of_B各ポートX)ですが、実行するとWarning: remote port forwarding failed for listen port X

Sshdに入る/var/log/secureサーバー上で次のエラーが表示されます:

bind: Address already in use
error: bind: Address already in use
error: channel_setup_fwd_listener: cannot listen to port: X

解決するには、VPSを再起動する必要があります。それまでは、再接続の試行はすべて「リモートポート転送に失敗しました」というメッセージが表示され、機能しません。トンネルが止まるまで約4時間しか続かないようになりました。

VPSで何も変更されておらず、リバーストンネルエンドポイントとしてのみ機能する使い捨てのシングルユーザーマシンです。 CentOS 6.5でOpenSSH_5.3p1を実行しています。接続が失われたときに、sshdがその端のポートを閉じていないようです。その理由を説明するのに途方に暮れているか、またはほぼ完璧な動作の数か月後に今それが突然起こるのはなぜですか.

明確にするために、トンネルが失敗した後、sshdがポートをリッスンしない理由を最初に理解する必要があります。これは、sshdがポートを開いたままにし、ポートを閉じないことが原因であると思われます。それが主な問題のようです。期待どおりの動作(つまり、ポートをすぐに閉じてスクリプトを再接続できるようにする)を数ヶ月行った後、何が原因でこのように動作するのかわかりません。

27
Justin Mrkva

MadHatterに同意します。これは、機能していないssh接続からのポート転送である可能性が高いということです。現在の問題が別の問題であることが判明した場合でも、遅かれ早かれ、このような機能しないssh接続に遭遇すると予想できます。

このような機能しない接続が発生する可能性のある方法は3つあります。

  • 接続のもう一方の端が完全にアイドル状態である間に、2つのエンドポイントの1つがリブートされました。
  • 2つのエンドポイントの1つが接続を閉じましたが、接続が閉じられたときに、接続で一時的な障害が発生しました。接続が閉じられた後、停止は数分間続いたため、もう一方の端は閉じられた接続について知ることはありませんでした。
  • 接続はまだssh接続の両方のエンドポイントで完全に機能していますが、誰かがそれらの間にどこかにステートフルデバイスを置いており、アイドル状態のために接続がタイムアウトしました。このステートフルデバイスは、NATまたはファイアウォールのいずれかです。すでに言及したファイアウォールは、最も疑わしいものです。

上記の3つのうちどれが起こっているかを把握することは、3つすべてに対処する方法があるため、それほど重要ではありません。それがキープアライブメッセージの使用です。

sshd_configClientAliveIntervalキーワードと、ssh_configまたは~/.ssh/configServerAliveInterval間隔を調べる必要があります。

ループでsshコマンドを実行すると問題なく動作します。何らかの理由で接続が失敗したときにサーバーにフラッディングが発生しないように、ループにもスリープを挿入することをお勧めします。

サーバー上で接続が終了する前にクライアントが再接続すると、新しいssh接続は有効であるがポート転送がない状況になる可能性があります。これを回避するには、クライアント側でExitOnForwardFailureキーワードを使用する必要があります。

29
kasperd

そのサーバーのポートをバインドしているプロセスを見つけることができます

Sudo netstat -apn|grep -w X

それは半端なsshdである可能性が非常に高いようですが、データを持つことができると仮定するのはなぜですか?これは、スクリプトがトンネルを再起動する前に信号9を送信するPIDを見つけるのに良い方法でもあります。

4
MadHatter

私にとっては、sshトンネルが切断されると、接続がリセットされるまでにしばらく時間がかかるため、sshプロセスが引き続きブロックされ、アクティブなトンネルがなくなり、理由がわかりません。回避策は、ssh-fでバックグラウンドに配置し、古い接続がリセットされるのを待たずに新しい接続を生成することです。 -o ExitOnForwardFailure=yesを使用して、新しいプロセスの数を制限できます。 -o ServerAliveInterval=60は、現在の接続の信頼性を向上させます。

sshコマンドを頻繁に繰り返すことができます。たとえば、cron、または次のようなスクリプトのループで、sshコマンドを実行します。 3分ごと:

while (1)
do
    ssh -f user@hostname -Rport:Host:hostport -N -o ExitOnForwardFailure=yes -o ServerAliveInterval=60
    sleep 180
done
3
Stephen Quan

私の経験では、リモートシステムで「何か」がまだ実行されている場合、sshは正常に終了しないという少し厄介な癖を持っています。例えば。バックグラウンドで開始しました。これは次の方法で再現できます。

ssh <server>
while true; do  sleep 60; done&
exit

Sshはログアウトしますが、実際にはセッションを閉じません-リモートプロセスが終了するまで(「trueの間」のループであるため、終了しません)。それは同様のことが起こっている可能性があります-あなたのセッションにはsshによって引き起こされている「スタック」プロセスがあります。ポートは使用中のままであるため、ローカルプロセスで再利用することはできません。

1
Sobrique