问题

问题

语境

我有一个用于网络的个人服务器。有时我需要通过 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 流处理。所以我想知道我是否也可以在 中直接在端口 443 上使用它nginx。这个想法是,如果它识别 HTTP(S) 或其他所有内容,nginx则可以选择使用该模块。httpstream

问题

因此,我有两个问题:

  • 甚至能够做到这样的区分吗?(我甚至不确定我是否能够同时在和块nginx中监听端口 443。 )httpstream
  • 如果是这样,那么该设置是否存在明显的性能问题?(例如,我考虑的是 SFTP 的传输速度,而不是 SSH 本身。)

答案1

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

答案2

我有一个工作配置,使用 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

我的配置使用了docker版本的nginx,但是没有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 的东西,你必须添加一些 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"

你应该已经连接上了。

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

您在 http {} 部分中配置的常规 http 服务器应该处理以下问题:

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

最好的事情是,您不需要 sslh、stunnel、proxytunnel 或其他工具来实现这一点。您只需要一个较新的 nginx 和 openssl。希望这对某些人有帮助。它有助于我深入研究这些东西。

答案3

或者,你可以通过 HTTP/S 连接通过 nginx 进行代理隧道 ssh

看一看:代理隧道

答案4

您可以设置一个 iptables 规则,将您知名的咖啡馆的 443 端口连接转发到 22 端口。或者,将流量从互联网上其他地方的端口中继反弹,从而更改 pirt 号码。

仅仅尝试用 nginx 来解决问题是行不通的。

相关内容