私は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
はすでにraw TCPストリーム処理をサポートしているので、nginx
でもポート443で直接使用できるかどうか疑問に思っていました。 nginx
がHTTP(S)を認識する場合はhttp
モジュールを使用し、それ以外の場合はstream
を使用することを選択できます。
その文脈で、私は2つの質問があります:
nginx
はそのような区別を行うことさえできますか? (http
ブロックとstream
ブロックの両方で同時にポート443をリッスンできるかどうかさえわかりません。)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;
}
}
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のみが必要です。これが誰かを助けることを願っています。それは私がそのことを掘り下げるのを助けるでしょう。
または、HTTP/S接続でnginxを介してsshをプロキシトンネルすることもできます
見てみましょう: proxytunnel
この質問は、少し前に回答した別の質問とわずかに関連しています。
はい、技術的にはssh
とhttps
のトラフィックを区別し、接続を適切にルーティングすることができます。しかし、私の知る限り、nginxは現在そのようなサポートを持っていません。
ただし、sshd
ポートに加えてhttps
ポートで直接ssh
を直接実行するだけで実行できます( /usr/sbin/sshd -p 22 -p 443
) 、および/またはファイアウォールおよび/またはポートノッキングを使用して、ポート443
への接続がルーティングされる場所を区別します。
Iptablesルールを設定して、よく知られているカフェからの接続をポート443でポート22に転送できます。または、インターネット上の他の場所にあるポートリレーからトラフィックをバウンスして、pirt番号を変更します。
Nginxで問題を解決しようとしてもうまくいきません。
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/
私の知る限り、現在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
クライアントは、この情報を使用して実装できます。
たぶん、あなたはnginScriptを使用して独自のマルチプレクサを実装できますか?概要についてはこちらを参照してください: https://www.nginx.com/blog/introduction-nginscript/
SSHとHTTPSのプロトコル多重化をサポートするnginxのメンテナンスされていないパッチが存在します: https://github.com/shawnl/nginx-ssh
しかし、もう維持されていません。探しているものをサポートする非nginxプロジェクトは次のとおりです: https://github.com/yrutschle/sslh
Nginxおよびsshサーバーの前でSSLHを使用することをお勧めします。