nginx 可以在同一个端口上同时提供 SSH 和 HTTP(S) 服务吗?

Joh*_*hnW 21 multiplexing nginx

语境

我有一个用于网络的个人服务器。我有时需要 SSH/SFTP 到它。

免责声明:我对nginx内部结构的经验很少。

问题

今天早上,我发现一家知名咖啡馆连锁店的免费 wifi 阻止了 SSH(实际上,他们阻止了任何不在 80/443 上的东西)。但是当我需要 SSH 时,我需要它,所以我寻找在同一端口上共享 SSH 和 HTTPS 的方法。

我看的

我查看了一些可以在端口 443 上运行的可能解决方案:

  • SSHL:SSH/OpenVPN/HTTPS 多路复用器;
  • OpenVPN:VPN 解决方案具有用于 OpenVPN 和 HTTPS 的内置多路复用器;
  • HAProxy:网络服务器/负载平衡器也可以多路复用所有内容。

所有这些看起来都很简单,我真的不喜欢添加层和复杂性的事实,并且可能会在不太可能的情况下放慢速度,因为我需要在 443 上使用 SSH。

将 nginx 放入混合中

我知道它nginx已经支持原始 TCP 流处理。所以我想知道我是否可以直接在nginx. 这个想法是,如果模块识别 HTTP(S) 或其他所有内容,则nginx可以选择使用该http模块stream

问题

在这种情况下,我有两个问题:

  • nginx即使能够做这样的区别?(我什至不确定我是否能够同时httpstream块和块中侦听端口 443。)
  • 如果是这样,该设置是否会存在明显的性能问题?(例如,我正在考虑使用 SFTP 的传输速度,而不是真正的 SSH 本身。)

小智 19

由于 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • ssh 和 (nginx) https 服务器是否可以在同一台主机上?我假设您需要让 https 在端口 444 上“侦听”或其他什么,并将侦听 443 的 ssh 预读引导到端口 444 以获取 https? (2认同)

tux*_*tux 11

我有一个工作配置,使用 nginx 流模块在端口 443 上通过 tls 隧道传输 ssh。我还在同一端口上通过 TLS 和普通 HTTP 执行 XMPP。我通过 ALPN 进行多路复用。

(您需要 nginx > 1.13.10 才能将 ssl_preread 模块与 alpn 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您想使用 XMPP 的东西,您必须添加一些 SRV 记录以指向您的服务器 443 端口,请参阅https://xmpp.org/extensions/xep-0368.html

如果您想连接到您的 ssh 服务器,您必须将您的 ssh 会话包装在一个 ssl 会话中,该会话发送您在流配置中定义的 ALPN 字符串。我在上面的例子中使用了“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"
Run Code Online (Sandbox Code Playgroud)

你应该连接。

我还应该注意,我使用 proxy_protocol 在传递到我的后端时保留客户端标头和 IP 地址。

您在 http {} 部分配置的普通 http 服务器应该处理这个问题:

server {
  listen 8443 ssl proxy_protocol;
  # ...
}
Run Code Online (Sandbox Code Playgroud)

最好的事情是,您不需要像 sslh、stunnel、proxytunnel 或其他工具来完成这项工作。你只需要一个更新的 nginx 和 openssl。希望这可以帮助某人。它会帮助我深入研究这些东西。


小智 5

或者,您可以使用 HTTP/S 连接通过 nginx 进行 proxytunnel ssh

看一下:proxytunnel


Gea*_*Lin 1

据我所知,目前nginx不支持。

SSH-2中,客户端将向服务器发送一条 hello 消息:

当连接建立后,双方必须发送一个标识字符串。该标识字符串必须是

 SSH-protoversion-softwareversion SP comments CR LF
Run Code Online (Sandbox Code Playgroud)

TLS 1.2中,客户端需要先发送:

  Client                                                Server

  ClientHello                   -------->
                                                   ServerHello
                                            [ChangeCipherSpec]
                                <--------             Finished
  [ChangeCipherSpec]
  Finished                      -------->
  Application Data              <------->     Application Data
Run Code Online (Sandbox Code Playgroud)

客户可以使用此信息进行实施。