web-dev-qa-db-ja.com

nginxは同じポートでSSHとHTTP(S)を同時に提供できますか?

環境

私はWebに使用するパーソナルサーバーを持っています。 SSH/SFTPが必要になることもあります。

Disclamer:nginx internalsの経験はほとんどありません。

問題

今朝、有名なカフェチェーンの無料Wi-FiがSSHをブロックしていることを突き止めました(実際、SSHは80/443以外のものをブロックしています)。しかし、SSHが必要なときに必要なので、同じポートでSSHとHTTPSを共有する方法を探しました。

私が見たもの

私はポート443で実行できるいくつかの可能なソリューションを見てきました。

  • SSHL:SSH/OpenVPN/HTTPSマルチプレクサ;
  • OpenVPN:VPNソリューションには、OpenVPNおよびHTTPS用の組み込みマルチプレクサーがあります。
  • HAProxy :Webサーバー/ロードバランサーもすべてを多重化できます。

これらはすべて非常に単純明快に見えますしかしレイヤーと複雑さを追加するという事実はあまり好きではありませんたぶん遅くなる万が一、443でSSHを実行する必要があるという事態が発生しました。

Nginxをミックスに入れる

nginxはすでにraw TCPストリーム処理をサポートしているので、nginxでもポート443で直接使用できるかどうか疑問に思っていました。 nginxがHTTP(S)を認識する場合はhttpモジュールを使用し、それ以外の場合はstreamを使用することを選択できます。

ご質問

その文脈で、私は2つの質問があります:

  • nginxはそのような区別を行うことさえできますか? (httpブロックとstreamブロックの両方で同時にポート443をリッスンできるかどうかさえわかりません。)
  • もしそうなら、そのセットアップで露骨なパフォーマンスの問題はありますか? (たとえば、SSH自体ではなく、SFTPでの転送速度を考えています。)
16
JohnW

Nginxバージョン1.15.2以降、新しい変数$ssl_preread_protocolが追加されました。そして、公式ブログでは、この変数を使用して同じポートでHTTPSとSSHを多重化する方法についての投稿を追加しました https://www.nginx.com/blog/running-non-ssl-protocols-over-ssl-port -nginx-1-15-2 /

SSH(デフォルト)およびHTTPSの構成例:

stream {
    upstream ssh {
        server 192.0.2.1:22;
    }

    upstream web {
        server 192.0.2.2:443;
    }

    map $ssl_preread_protocol $upstream {
        default ssh;
        "TLSv1.2" web;
    }

    # SSH and SSL on the same port
    server {
        listen 443;

        proxy_pass $upstream;
        ssl_preread on;
    }
}
14
sattellite

Nginxストリームモジュールを使用して、ポート443でtlsを介してSSHをトンネリングする有効な構成があります。また、XMPP over TLSと通常のHTTPを同じポートで実行します。私はALPNを介して多重化を行います。

(alpnでssl_prereadモジュールを使用するには、nginx> 1.13.10が必要です http://nginx.org/en/docs/stream/ngx_stream_ssl_preread_module.html#ssl_preread

私の構成ではnginxのdockerバージョンを使用していますが、dockerがなくても機能するはずです。

stream {
    # check ALPN for xmpp client or server and redirect to local ssl termination endpoints
    map $ssl_preread_alpn_protocols $ssl_multiplexer {
        "xmpp-client"     127.0.0.1:5422;
        "xmpp-server"     127.0.0.1:5469;
        "identifyssh"     127.0.0.1:8822;
        default           127.0.0.1:8443;
    }

    server {
        listen 443;
        ssl_preread on;
        proxy_pass $ssl_multiplexer;
        proxy_protocol on;
        set_real_ip_from  172.18.0.0/32;
    }

    # ssl termination for c2s connections
    server {
        listen 5422 ssl proxy_protocol;
        # ... <- tls keys and options here
        proxy_ssl off;
        proxy_pass ejabberd:5222;
    }

    # ssl termination for s2s connections
    server {
        listen 5469 ssl proxy_protocol;
        # ... <- tls keys and options here
        proxy_ssl off;
        proxy_pass ejabberd:5269;
    }

    # ssl termination for ssh connections
    server {
        listen 8822 ssl proxy_protocol;
        # ... <- tls keys and options here
        proxy_ssl off;
        proxy_pass yourserver:22;
    }
}

XMPPのものを使用する場合は、サーバーの443ポートを指すようにSRVレコードを追加する必要があります。詳細は https://xmpp.org/extensions/xep-0368.html を参照してください

Sshサーバーに接続する場合は、ストリーム構成で定義したALPN文字列を送信するsslセッションでsshセッションをラップする必要があります。上記の例では「identifyssh」を使用しました。何でも使用できますが、正式に定義された名前と衝突しないようにしてください: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol- ids

クライアントから準備済みサーバーへのsshセッションを開始するには、次のコマンドを使用します。

ssh you@yourserver -o "ProxyCommand openssl s_client -alpn identifyssh -ign_eof -connect yourserver:443"

そして接続する必要があります。

また、バックエンドに渡す間、proxy_protocolを使用してクライアントのヘッダーとIPアドレスを保持していることにも注意してください。

Http {}セクションで構成された通常のhttpサーバーがこれを処理します。

server {
  listen 8443 ssl proxy_protocol;
  # ...
}

最良のことは、これを機能させるためにsslh、stunnel、proxytunnelなどのツールを必要としないことです。新しいnginxとopensslのみが必要です。これが誰かを助けることを願っています。それは私がそのことを掘り下げるのを助けるでしょう。

6
tux

または、HTTP/S接続でnginxを介してsshをプロキシトンネルすることもできます

見てみましょう: proxytunnel

4
mtsdev

この質問は、少し前に回答した別の質問とわずかに関連しています。

https://stackoverflow.com/questions/34741571/nginx-tcp-forwarding-based-on-hostname/34958192#34958192

はい、技術的にはsshhttpsのトラフィックを区別し、接続を適切にルーティングすることができます。しかし、私の知る限り、nginxは現在そのようなサポートを持っていません。

ただし、sshdポートに加えてhttpsポートで直接sshを直接実行するだけで実行できます( /usr/sbin/sshd -p 22 -p 443 ) 、および/またはファイアウォールおよび/またはポートノッキングを使用して、ポート443への接続がルーティングされる場所を区別します。

2
cnst

Iptablesルールを設定して、よく知られているカフェからの接続をポート443でポート22に転送できます。または、インターネット上の他の場所にあるポートリレーからトラフィックをバウンスして、pirt番号を変更します。

Nginxで問題を解決しようとしてもうまくいきません。

2
symcbean

Nginxバージョン1.9.0、NGINXはngx_stream_core_moduleモジュールをサポートしているため、-with-streamで有効にする必要があります。ストリームモジュールが有効な場合、sshプロトコルtcpプロキシが可能です

stream {
upstream ssh {
    server 192.168.1.12:22;
}
    server {
    listen        12345;
    proxy_pass    ssh;

} }

https://www.nginx.com/resources/admin-guide/tcp-load-balancing/

1
Hendi Fauzi

私の知る限り、現在nginxはそれをサポートしていません。

SSH-2 では、クライアントはhelloメッセージをサーバーに送信します。

接続が確立されると、両側が識別文字列を送信する必要があります。この識別文字列は

 SSH-protoversion-softwareversion SP comments CR LF

TLS 1.2 では、クライアントは最初に送信する必要があります。

  Client                                                Server

  ClientHello                   -------->
                                                   ServerHello
                                            [ChangeCipherSpec]
                                <--------             Finished
  [ChangeCipherSpec]
  Finished                      -------->
  Application Data              <------->     Application Data

クライアントは、この情報を使用して実装できます。

1
Gea-Suan Lin

たぶん、あなたはnginScriptを使用して独自のマルチプレクサを実装できますか?概要についてはこちらを参照してください: https://www.nginx.com/blog/introduction-nginscript/

0
Thraidh

SSHとHTTPSのプロトコル多重化をサポートするnginxのメンテナンスされていないパッチが存在します: https://github.com/shawnl/nginx-ssh

しかし、もう維持されていません。探しているものをサポートする非nginxプロジェクトは次のとおりです: https://github.com/yrutschle/sslh

Nginxおよびsshサーバーの前でSSLHを使用することをお勧めします。

0
kensai