Kann nginx SSH und HTTP (S) gleichzeitig am selben Port bereitstellen?

7854
JohnW

Kontext

Ich habe einen persönlichen Server, den ich für das Web verwende. Ich muss manchmal SSH / SFTP dazu.

Disclamer: Ich habe sehr wenig Erfahrung mit nginxInternen.

Problem

Heute morgen habe ich herausgefunden, dass das kostenlose WLAN in einer bekannten Café-Kette SSH blockierte (tatsächlich blockieren sie alles, was nicht auf 80/443 ist). Aber wenn ich SSH brauche, brauche ich es, also habe ich nach Möglichkeiten gesucht, SSH und HTTPS über denselben Port zu teilen.

Was ich mir angesehen habe

Ich habe mir einige mögliche Lösungen angesehen, die auf Port 443 laufen können:

  • SSHL: einen SSH / OpenVPN / HTTPS-Multiplexer;
  • OpenVPN: Eine VPN-Lösung verfügt über einen integrierten Multiplexer für OpenVPN und HTTPS.
  • HAProxy: Ein Webserver / Load Balancer kann auch alles multiplexen.

All dies scheint ziemlich geradlinig zu sein, aber ich mag es nicht wirklich, Ebenen und Komplexität hinzuzufügen und möglicherweise etwas zu verlangsamen, nur in dem unwahrscheinlichen Fall, dass ich SSH auf 443 benötige.

Nginx in die Mischung geben

Ich weiß, dass nginxdie Verarbeitung roher TCP-Streams bereits unterstützt wird. Also habe ich mich gefragt, ob ich das an Port 443 auch direkt in verwenden kann nginx. Die Idee ist, dass nginxdas httpModul verwendet werden könnte, wenn es HTTP (S) oder streamalles andere erkennt .

Fragen

In diesem Zusammenhang habe ich zwei Fragen:

  • Ist nginxsogar eine solche Unterscheidung möglich? (Ich bin mir nicht mal sicher, ob ich Port 443 gleichzeitig im httpund im streamBlock abhören kann.)
  • Wenn ja, gäbe es bei diesem Setup ein offensichtliches Leistungsproblem? (Ich denke beispielsweise an die Übertragungsgeschwindigkeit mit SFTP, nicht wirklich an SSH per se.)
5
Ich weiß genug über diese Protokolle, um zu erklären, inwieweit eine solche Protokollerkennung möglich ist. Ich weiß jedoch nicht, wozu Nginx fähig ist. Der Name "Stream" klingt nicht nach einer Funktion, die eine Protokollerkennung durchführen kann. Unabhängig davon, was Sie auf der Serverseite verwenden, müssen Sie entweder den SSH-Verkehr in einem anderen Protokoll kapseln oder einen SSH-Client verwenden, der aktuell genug ist, um vor dem Server sprechen zu können. Sich auf den Server zu verlassen, um das Protokoll eines Clients zu erkennen, der noch nicht gesprochen hat, wäre fragil. kasperd vor 7 Jahren 0
Die Unterstützung für "nginx" scheint ziemlich klein zu sein, und es scheint, dass sie sich nur auf die Portnummer stützt, um den Verkehr zu "routen". Soweit ich verstanden habe, ist der http-Block lediglich eine Möglichkeit, das richtige Modul für den richtigen entsprechenden Server zu laden, der auf einen bestimmten Port wartet. Dieses Modul wird wiederum die gesamte "SNI" -Magie ausführen. Aber ich bin kein Experte und wollte nur sicherstellen, dass ich das richtig verstanden habe. JohnW vor 7 Jahren 0
Mir ist nicht klar, warum Sie überhaupt nach Nginx fragen. Es scheint, Sie haben keine Erfahrung mit Nginx und keine Beweise dafür, dass es in der Lage sein sollte, das zu tun, was Sie von Anfang an verlangen. Wenn Sie deutlich gemacht haben, wie Ihr aktuelles Setup aussieht, könnten Sie wahrscheinlich eine viel bessere Antwort erhalten. kasperd vor 7 Jahren 1
Das heißt, "SNI" tritt auf TLS-Ebene auf: Wenn es kein "SNI" gibt, kann "nginx" ** stattdessen standardmäßig streamen. JohnW vor 7 Jahren 0

9 Antworten auf die Frage

6
sattellite

Seit nginx Version 1.15.2 neue Variable hinzugefügt $ssl_preread_protocol. In einem offiziellen Blog wurde ein Beitrag über die Verwendung dieser Variablen für das Multiplexen von HTTPS und SSH auf demselben Port https://www.nginx.com/blog/running-non-ssl-protocols-over-ssl-port-nginx-1 hinzugefügt -15-2 /

Beispiel für die Konfiguration von SSH (standardmäßig) und 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; } } 
Ist es möglich, dass sich sowohl der SSH-Server als auch der (Nginx) -HTPS-Server auf demselben Host befinden? Ich gehe davon aus, dass Sie https auf Port 444 oder etwas anderes "hören" müssen, und den ssh-Preread, der auf 443 zuhört, an Port 444 für https weiterleitet? starbeamrainbowlabs vor 5 Jahren 1
@starbeamrainbowlabs Sie können nicht beide auf 443 setzen, aber Sie können Unix Domain Socket verwenden, sodass Sie nicht zwei Nginx-Prozesse ausführen müssen. Sie können unix: / run / nginx.sock` in http> Serverblöcken abhören. kissgyorgy vor 5 Jahren 0
4
mtsdev

Oder Sie können ssh über Ihren Nginx mit HTTP / S-Verbindung proxytunnel

Schauen Sie doch mal rein : Proxytunnel

3
tux

Ich habe eine funktionierende Konfiguration, die ssh über TLS auf Port 443 unter Verwendung des Stream-Moduls nginx tunnelt. Ich mache auch XMPP über TLS und normales HTTP am selben Port. Ich mache das Multiplexen über ALPN.

(Sie benötigen nginx> 1.13.10, um das Modul ssl_preread mit alpn http://nginx.org/en/docs/stream/ngx_stream_ssl_preread_module.html#ssl_preread zu verwenden. )

Meine Konfiguration verwendet die Docker-Version von nginx, sollte aber auch ohne Docker funktionieren.

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; } } 

Wenn Sie das XMPP-Material verwenden möchten, müssen Sie einige SRV-Einträge hinzufügen, um auf den Port Ihrer Server zu verweisen. Siehe https://xmpp.org/extensions/xep-0368.html

Wenn Sie eine Verbindung zu Ihrem SSH-Server herstellen möchten, müssen Sie Ihre SSH-Sitzung in eine SSL-Sitzung einschließen, die die ALPN-Zeichenfolge sendet, die Sie in Ihrer Stream-Konfiguration definiert haben. Ich habe in dem obigen Beispiel "IDENTSSH" verwendet. Sie können alles verwenden, aber versuchen Sie nicht, mit den offiziell definierten Namen zu kollidieren: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids

So starten Sie die SSH-Sitzung von Ihrem Client zu Ihrem vorbereiteten Server:

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

Und du solltest verbunden sein.

Ich sollte auch beachten, dass ich das Proxy_Protokoll verwende, um die Header und IP-Adressen der Clients beizubehalten, während sie an meine Backends weitergeleitet werden.

Ihr normaler http-Server, der im Abschnitt http {} konfiguriert ist, sollte dies beachten:

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

Das Beste ist, dass Sie keine Tools wie sslh, stunnel, Proxytunnel oder andere benötigen, um dies zu erreichen. Sie benötigen nur ein neueres Nginx und OpenSSL. Hoffe das hilft jemandem. Es würde mir helfen, mich in das Zeug einzuarbeiten.

2
cnst

Diese Frage hat etwas mit einer anderen zu tun, die ich vor einiger Zeit beantwortet habe:

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

Ja, es ist technisch möglich, zwischen Verkehr sshund httpsVerkehr zu unterscheiden und die Verbindung entsprechend zu routen. nginx hat meines Wissens jedoch derzeit keine solche Unterstützung.

Sie könnten jedoch einfach sshddirekt am httpsPort zusätzlich zu sshone ( /usr/sbin/sshd -p 22 -p 443) laufen und / oder die Firewall und / oder das Port-Klopfen verwenden, um zu unterscheiden, wohin die Verbindungen zum Port 443geleitet werden.

Sieht aus, als hätte nginx jetzt Unterstützung für den [ngx_stream_ssl_preload_mode] (https://nginx.org/en/docs/stream/ngx_stream_ssl_preread_module.html). starbeamrainbowlabs vor 5 Jahren 0
2
symcbean

Sie können eine iptables-Regel einrichten, um Verbindungen von Ihrem bekannten Café an Port 443 an Port 22 weiterzuleiten. Alternativ können Sie den Verkehr von einem Port-Relay an anderer Stelle im Internet abprallen lassen, indem Sie die Pirt-Nummer ändern.

Nur zu versuchen, das Problem mit Nginx zu lösen, wird nicht funktionieren.

1
Gea-Suan Lin

Soweit ich weiß, wird es derzeit von nginx nicht unterstützt.

In SSH-2 sendet der Client eine Hallo-Nachricht an den Server:

Wenn die Verbindung hergestellt wurde, MÜSSEN beide Seiten einen Identifikationsstring senden. Diese Identifikationszeichenfolge MUSS sein

 SSH-protoversion-softwareversion SP comments CR LF 

In TLS 1.2 müssen Clients zuerst senden:

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

Kunden können diese Informationen für die Implementierung verwenden.

Diese Antwort ist etwas ungenau. In der Vergangenheit hatte das SSH-Protokoll den Server zuerst zum Sprechen. In SSH-2 darf der Client jedoch sprechen, ohne darauf zu warten, dass der Server zuerst spricht. Jeder OpenSSH-Client, der weniger als ein paar Jahre alt ist, spricht, ohne dass der Server zuerst sprechen muss - solange Sie die SSH-1-Unterstützung im Client nicht aktivieren. kasperd vor 7 Jahren 1
Ja, du hast recht, ich werde meine Antwort korrigieren. Gea-Suan Lin vor 7 Jahren 0
1
Hendi Fauzi

Seit Nginx Version 1.9.0 unterstützt NGINX das Modul ngx_stream_core_module. Es sollte mit dem --with-stream aktiviert werden. Wenn das Stream-Modul aktiviert ist, können sie das ssh-Protokoll für den Proxy-Proxy verwenden

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/

Dies lässt Sie nicht multiplexen. Ivan Vučica vor 6 Jahren 2
0
kensai

Es ist ein nicht gepflegter Patch für nginx vorhanden, der das Protokollmultiplexing für SSH und HTTPS unterstützt: https://github.com/shawnl/nginx-ssh

Es wird jedoch nicht mehr gepflegt, ein Nicht-Nginx-Projekt, das unterstützt, wonach Sie suchen: https://github.com/yrutschle/sslh

Ich schlage vor, Sie verwenden SSLH vor Ihrem Nginx- und SSH-Server.

0
Thraidh

Vielleicht können Sie mit nginScript Ihren eigenen Multiplexer implementieren? Hier finden Sie eine Einführung: https://www.nginx.com/blog/introduction-nginscript/