SSHトンネルを確実に開いたままにする方法


234

仕事からのSSHトンネルを使用して、さまざまなアイドティックファイアウォールを迂回します(上司には問題ありません:))。問題は、しばらくすると通常ssh接続がハングし、トンネルが壊れることです。

少なくともトンネルを自動的に監視できれば、トンネルがハングしたときに再開できますが、それを行う方法すら考えていません。

もちろん、私のssh接続がハングするのを防ぐ方法を教えてくれる人にはボーナスポイントです!


非アクティブであるため、トンネルは死んでいますか?携帯電話からポートをトンネリングするときにこの問題が発生したため、watch次のようなコマンドを使用して接続で「有効」にするためのダミーコマンドの接続を最終的に終了しましたwatch -n1 60 echo "wiiiii"。トンネルは、ネットワークが壊れているか、使用しない限り死にません。
erm3nda

回答:


280

autosshが必要なようです。これにより、sshトンネルが監視され、必要に応じて再起動されます。数年使用してきましたが、うまく機能しているようです。

autossh -M 20000 -f -N your_public_server -R 1234:localhost:22 -C

-Mパラメーターの詳細はこちら


2
autosshの場合は+1、ブリキに記載されていることを行います。その機能の一部は、キープアライブスタイルのパケットを送信して、あらゆる種類のタイムアウトを防ぐことでもあると思います。
akent

30
autossh回答にトンネルの例を使用できますか?
Ehteshチョードリー

5
autossh -f -nNT -i ~/keypair.pem -R 2000:localhost:22 username@myoutsidebox.com リモート端末を作成せずにautosshをバックグラウンドに配置できる-nNTと、.pemファイルを使用するSSHの-iオプションを使用して、これを設定していることに気付くかもしれません。接続を常に開いたままにする場合は、追加のセットアップを行うことをお勧めします。
ジャッケル

2
価値があるものについては、通常は-Mパラメーターを省略するほうが良いようです:bugs.debian.org/cgi-bin/bugreport.cgi
bug=

2
ネットワーク変更時に再試行するためにこれを行いましたが、私にとってはうまくいきます:autossh -M 0 -o "ServerAliveInterval 10" -o "ServerAliveCountMax 2" -L 9999:localhost:19999 server@example.com
Luke Stanley

39

すべてのステートフルファイアウォールは、その接続のパケットをしばらく見ないと接続を忘れます(接続を閉じずに両端が停止した状態で状態テーブルがいっぱいになるのを防ぐため)。ほとんどのTCP実装は、長い時間後に相手側からの連絡なしでキープアライブパケットを送信します(2時間が一般的な値です)。ただし、キープアライブパケットを送信する前に接続を忘れるステートフルファイアウォールが存在する場合、存続期間は長いがアイドル状態の接続は終了します。

その場合、解決策は接続がアイドル状態になるのを防ぐことです。OpenSSHには、ServerAliveIntervalというオプションがあり、これを使用して接続が長時間アイドル状態になるのを防ぐことができます(ボーナスとして、接続がアイドル状態であってもピアがより早く消滅したことを検出します)。


指定された間隔は秒単位であるため、微調整を行うことができます。ステートフルファイアウォールのアイドルタイムアウトが5分の場合、接続を開いたままにするには60秒または120秒で十分です。これは、ホームルーターを介してsshセッションを開いたままにする方法の1つです。
ダレンホール

ありがとう、これは助けた。ただし、(ここの下位の回答、superuser.com / a / 146641/115515から)ServerAliveCountMaxではなくServerAliveIntervalを指定すると、sshが意図したよりも早く切断されることがあります。
メタマット

4
@metamatt、あなたが参照するより低いランクの答えは、正当な理由でより低いランクです:それは間違っています。
ランバート

24

独自のMacまたはLinuxマシンで、sshを構成して、サーバーsshを3分ごとに有効に保ちます。ターミナルを開いて、あなたの家であなたの見えない.sshに行きます:

cd ~/.ssh/ 

次に、以下を使用して1行の構成ファイルを作成します。

echo "ServerAliveInterval 180" >> config

以下も追加する必要があります。

ServerAliveCountMax xxxx (high number)

デフォルトは3なので、ServerAliveInterval 180は9分後に送信を停止します(ServerAliveIntervalで指定された3分の間隔のうち3つ)。


2
既に構成ファイルがある場合、コマンドは推奨されないことに注意してください。リダイレクトに>>を使用する方がはるかに良いでしょう!
ペルチェ

なぜServerAliveInterval 1806分を与えるのですか?直観でこれを試してみます:180/60 == 3。では、ServerAliveInterval30秒の倍数で動作しますか?
nemesisfixx

@mcnemesis:ServerAliveInterval 180は3分を意味します。ServerAliveCountMaxのデフォルトの3は、これらの間隔のうち3つを意味するため、9分です。
メタマット

2
ServerAliveCountMaxについて言及してくれたことに感謝し、ServerAliveCountMaxを指定せずにServerAliveIntervalを指定した場合はどうなるかについて、この回答を投票しています。しかし、前述のコメントのように、「後で送信を停止する」の計算が間違っていることに気付きました。これらのオプションに関する情報を提供するだけで、cdコマンドとechoコマンドでそれらを適用する方法が示されない場合、この答えがより役立つと思います。
メタマット

20
ServerAliveCountMaxを「高い数値」に設定しても意味がないため、ダウン投票。ServerAliveCountMaxは、「キープアライブ」メッセージの送信を試行する回数を指定します。デフォルトは3なので、ServerAliveInterval 180では、9分後にサーバーが応答しなかった場合にのみ送信を停止します。この場合、接続はおそらく正常で実際に停止しています。
ランバート14

22

次のBashスクリプトを使用して、前のトンネルが停止したときに新しいsshトンネルを生成し続けました。スクリプトを使用すると、追加のパッケージをインストールしたくない場合やコンパイラを使用できない場合に便利です。

while true
do
  ssh <ssh_options> [user@]hostname
  sleep 15
done

これには、接続を自動的に確立するためのキーファイルが必要ですが、autosshの場合も同様です。


2
このスクリプトをautosshで使用する理由を追加する必要がありますか、それともこの方法のほうが簡単なのでしょうか?
kyrias

4
ssh自体がフリーズした場合、これは役に立ちませんか?
nafg

1
サーバーにインストールできない場合に役立ちます。autosshはプリインストールされておらず、官僚主義は非常に鈍い場合があります。
-quarkex

はい、インストールする必要はありません。リモートマシンにアクセスできるようにする唯一の方法として(リブート時にcrontabを実行するようにcrontabを設定することもあります)、1年間この方法でこれを行ってきました。失敗することはありません。さらに重要なことは、失敗しない理由を知っていることです。
sudo

16

Systemdはこれに最適です。

/etc/systemd/system/sshtunnel.serviceを含むサービスファイルを作成します。

[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コマンドを合わせて変更します)

  • これはユーザーとして実行されるsshtunnelため、最初にユーザーが存在することを確認してください
  • systemctl enable sshtunnel起動時に起動するように設定する問題
  • systemctl start sshtunnelすぐに開始する問題

2018年1月の更新:一部のディストリビューション(Fedora 27など)は、systemd initからのSSHの使用を防ぐためにSELinuxポリシーを使用する場合があります。この場合、必要な免除を提供するにはカスタムポリシーを作成する必要があります。


2
これは私の要点と非常によく似ています:gist.github.com/guettli/…フィードバックは大歓迎です!
ゲットリ

systemdシステムに最適です。使用した場合Restart=on-failure、SSHクライアントを手動で強制終了しても、終了したSSHクライアントとしてsystemd-by-systemd は正常に終了しません。
デビッドトンホーファー

ExecStartたとえばssh引数リストを作成するための引数として指定された(bash)スクリプトからsshを起動する場合は、基本的なチェックなどを行い、そのようにしてスクリプトから呼び出しますexec /bin/ssh -N ...。ここに私のコマンドがあります:exec /bin/ssh -N -oExitOnForwardFailure=Yes -oTCPKeepAlive=no -oServerAliveInterval=5 -oServerAliveCountMax=6 -i "${LOCAL_PRIVATE_KEY}" -L "${TUNNEL_INLET}:${TUNNEL_OUTLET}" "${REMOTE_USER}@${REMOTE_MACHINE}"どこTUNNEL_INLET="127.0.0.1:3307"TUNNEL_OUTLET="127.0.0.1:3306"
デビッドトンホーファー

10

ServerAliveCountMaxを誤解しているように見えます。私がドキュメントを理解しているように、接続が終了せずに無応答になる可能性のあるサーバーアライブメッセージの数です。したがって、ここで説明しているような場合、値を高く設定すると、ハングした接続が検出されて終了しないことが保証されます!

ファイアウォールが接続を忘れる問題を解決するには、ServerAliveIntervalを設定するだけで十分であり、ServerAliveCountMaxをLowのままにしておくと、発信側が接続に失敗した場合に失敗を通知して終了できます。

必要なのは、1)通常の状況下で接続を永続的に開いたままにする、2)接続障害を検出し、障害時に発信側を終了する、3)毎回sshコマンドを再発行することです。終了(どのように行うかはプラットフォームに大きく依存しますが、Jawaが推奨する「while while」スクリプトは、OS XIで実際に起動アイテムをセットアップする方法の1つです)。


9

ServerAliveInterval期限切れのNATセッションによってトンネルの問題が生成される場合は、常にSSHオプションを使用してください。

接続が完全にダウンした場合に備えて、常にリスポーン方法を使用します。ここには少なくとも3つのオプションがあります。

  • autosshプログラム
  • bashスクリプト(while true do ssh ...; sleep 5; done)はsleepコマンドを削除せず、sshすぐに失敗する可能性があり、再起動するプロセスが多すぎます
  • /etc/inittab、NATの背後にある別の国に出荷およびインストールされたボックスにアクセスし、ボックスにポートを転送せずに、sshトンネルを作成するように設定できます。

    tun1:2345:respawn:/usr/bin/ssh -i /path/to/rsaKey -f -N -o "ServerAliveInterval 180" -R 55002:localhost:22 user@publicip 'sleep 365d'
    
  • Ubuntuのupstartスクリプト(/etc/inittab使用不可):

    start on net-device-up IFACE=eth0
    stop on runlevel [01S6]
    respawn
    respawn limit 180 900
    exec ssh -i /path/to/rsaKey -N -o "ServerAliveInterval 180" -R 55002:localhost:22 user@publicip
    post-stop script
        sleep 5
    end script
    

または常に両方の方法を使用します。


1
SSH接続のすべてに必要ない場合のインラインオプションの+1
user1146334 14

「接続が完全にダウンした場合」と記述します。今、私は理解していません、autosshはそれ自体でどの問題を修正しますか?もちろん、数時間ケーブルを抜くなど、壊れた接続を処理するだろうと思いましたが、おそらくそうではないでしょうか?
マッドスキャーン

6

私はこれでこの問題を解決しました:

編集

~/.ssh/config

そして追加

ServerAliveInterval 15
ServerAliveCountMax 4

ssh_configのmanページによると:

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.

サーバーをpingするのは15秒ごとにかなり頻繁に思われます。
ランバート14

@Lambartしかし、接続が本当に不安定で接続を頻繁にドロップする場合、少なくとも接続の停止を検出し、より早く再試行する機会を与えます。
ビンキ14

4

ExitOnForwardFailure yes他の提案への良い補助です。接続してもポートフォワーディングを確立できない場合は、まったく接続していないのと同じくらい役に立たないでしょう。


これは非常に良い考えです。以前の接続がローカルホストよりもリモート側で早くタイムアウトしたと認識された場合、autosshは役に立たなくなります。この場合、ローカルホストは再度接続を試みますが、ポートが開いているため転送を確立できないためです。
ラウルサリナスモンテアグド

1

SSHトンネルを長期間維持する必要がありました。私のソリューションはLinuxサーバーから実行していました。これは、キーベースの認証を使用してsshを再生成する小さなCプログラムです。

ハングについてはわかりませんが、タイムアウトのためにトンネルが死んでしまいました。

私はリスポーナーにコードを提供したいと思っていますが、今は見つけられないようです。


1

sshセッションを再起動するのに役立つautosshなどのツールがありますが、「screen」コマンドを実行すると本当に便利だと思います。切断した後でも、sshセッションを再開できます。接続の信頼性がそれほど高くない場合に特に便利です。

...これがあなたに役立つなら、これが「正しい」答えであることを忘れないでください!;-)


7
...しかし、質問は、ターミナルセッションだけでなく、SSHトンネルを開いたままにする方法についてでした。画面は素晴らしいです!
akent

私はすでにスクリーンを使用していますが、それは私の問題を解決しません:-/けれどもあなたの答えをありがとう。
ペルチェ

1

ちょっとしたハックですが、これを維持するために画面を使用するのが好きです。現在、数週間実行されているリモート転送があります。

例、ローカルで開始:

screen
ssh -R ......

リモート転送が適用され、リモートコンピューターにシェルがある場合:

screen
Ctrl + a + d

これで、中断のないリモート転送ができました。トリックは、両端で画面を実行することです


1

これらのソリューションではパスワードログインを使用するたびにパスワードを再入力する必要があるため、バッチファイルにパスワードが含まれないようにテキストプロンプトとともにsshpassをループで使用したため、最近この問題が発生しました。

他の誰かが同じ問題を抱えている場合に備えて、このtheadで私のソリューションを共有したいと思いました:

#!/bin/bash
read -s -p "Password: " pass
while true
do
    sshpass -p "$pass" ssh user@address -p port
    sleep 1
done

0

以前のISPでも同様の問題が発生しました。私にとっては、tcp接続、ウェブサイトの訪問、メールの送信と同じでした。

解決策は、UDP経由でVPN接続を構成することでした(OpenVPNを使用していました)。この接続は、切断を引き起こしたものに対してより耐性がありました。その後、この接続を介して任意のサービスを実行できます。

接続にはまだ問題がある可能性がありますが、トンネルはより耐性があるため、sshセッションは切断されるのではなく、短いホールドアップを感じます。

これを行うには、独自のサーバーでセットアップできるVPNサービスがオンラインで必要になります。


0

autossh我々のニーズを(それは非常に最初の試みでサーバーに接続できない場合、それはエラーで存在する)満たしていない、私たちは純粋なbashのアプリケーションを書いています:https://github.com/aktos-io/link-サーバー付き

デフォルトでは、サーバー上のNODEのsshdポート(22)に逆トンネルを作成します。他のアクション(追加ポートの転送、接続時のメール送信など)を実行する必要がある場合は、スクリプトon-connecton-disconnectフォルダーを配置できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.