基于主机名的Nginx TCP转发

问题描述 投票:42回答:4

随着Nginx社区版本的TCP负载平衡的发布,我想混合使用OpenVPN和SSL传递数据。 Nginx知道如何路由流量的唯一方法是通过其域名。

 vpn1.app.com ─┬─► nginx at 10.0.0.1 ─┬─► vpn1  at 10.0.0.3
 vpn2.app.com ─┤                      ├─► vpn2  at 10.0.0.4
https.app.com ─┘                      └─► https at 10.0.0.5

我看过TCP guidesmodule documentation,但似乎没有被很好地引用。如果有人能指出我正确的方向,我将不胜感激。

有关ServerFault的相关问题:Can a Reverse Proxy use SNI with SSL pass through?

nginx tcp stream load-balancing virtualhost
4个回答
21
投票

假设

如果我理解正确,您实际上希望nginx侦听单个IP地址和TCP端口组合(例如listen 10.0.0.1:443),然后根据传入TCP流流量的特性,将其路由到3个不同的IP地址。

[您没有明确提到如何期望它区分所涉及的3个不同域,但是我的假设是,您假设它全部都是TLS,并且必须要使用某种TLS SNI(服务器名称指示)基于域的区分机制。

[我相信http://nginx.org/docs/中提供的与流相关的文档对于所涉及的模块是相当权威且详尽的(我在此处列出了所有模块,因为显然还没有可交叉引用的中心位置,例如,从“流核心”模块到子模块的引用都还没有((docs/stream/只是重定向回docs/),这确实很令人困惑,因为http://nginx.org/r/upstream之类的文档仅记录到适用于http,而没有关于stream的适用性的任何提及,即使指令的末尾大致相同):


答案

请注意,每个模块中的每个nginx指令都具有有限数量的适用Context

因此,不幸的是,这里根本没有任何指令可以监听到SNI!

相反,it's actually documented in stream_core引用“ stream_core”,正如您可能注意到的,它也与Different servers must listen on different address:port pairs.的使用方式相反,并且是对以下事实的明确表述:当前为listen directive works within the more-common http_core中的listen实现了SNI支持。


讨论

作为讨论点和解决建议,关于OpenVPN流量只是具有可监听SNI的TLS的假设也不一定正确(但我对OpenSSL或SNI不太熟悉:]]

  • 考虑到即使SNI在今天是被动侦听的,这也明显违背了TLS保证连接安全的承诺,因此,在将来的TLS版本中可能会发生变化。

  • 为了讨论,如果OpenVPN is

  • 仅使用TLS连接,并且如果is NOT使用TLS使用用户证书对用户进行身份验证(这会使MitM更加困难流,但仍然始终携带身份验证数据),然后,从理论上讲,[[如果nginx确实具有SNI支持,在http_core内的listen周围,那么您可能可以使用nginx(自stream起。)>最重要的是,我认为OpenVPN最好在其自己的基于UDP的协议上运行,在这种情况下,您可以为基于TCP的https的一个实例和另一个UDP-的实例使用相同的IP地址和端口号基于OpenVPN且没有冲突。

    最后,您可能会问,无论如何,流模块对您有用吗?我认为,它的目标受众将是(0),例如,基于客户端IP地址的listen与多个stream服务器进行负载均衡proxy_ssl is already supported in stream_proxy,和/或,(1), proxy_ssl的更直接且与协议无关的替代方法。

现在可以通过在Nginx 1.11.5中添加stream_proxy和在1.11.2中添加HTTP/2来实现。

这使Nginx可以读取TLS客户端Hello,并根据要使用的后端的SNI扩展来决定。

upstream

AS @Lochnair提到,您可以使用hashstunnel解决此问题。这是我的示例。

我的主机IP是stunnel,并且我使用keepalived绑定2虚拟IP到ngx_stream_ssl_preread module

ngx_stream_map module

因此,我可以通过不同的VIP使用相同的端口3306访问不同的MySQL服务。就像通过差异stream {

    map $ssl_preread_server_name $name {
        vpn1.app.com vpn1_backend;
        vpn2.app.com vpn2_backend;
        https.app.com https_backend;
        default https_default_backend;
    }

    upstream vpn1_backend {
        server 10.0.0.3:443;
    }

    upstream vpn2_backend {
        server 10.0.0.4:443;
    }

    upstream https_backend {
        server 10.0.0.5:443;
    }

    upstream https_default_backend {
        server 127.0.0.1:443;
    }

    server {
        listen 10.0.0.1:443;
        proxy_pass $name;
        ssl_preread on;
    }
}
通过相同的端口访问不同的HTTP服务一样。

ngx_stream_map module

我认为自2017年以来有所改变...

“ map”指令在/etc/nginx/nginx.conf中是不允许的>


60
投票
现在可以通过在Nginx 1.11.5中添加stream_proxy和在1.11.2中添加HTTP/2来实现。

5
投票
AS @Lochnair提到,您可以使用hashstunnel解决此问题。这是我的示例。

0
投票
我认为自2017年以来有所改变...
© www.soinside.com 2019 - 2024. All rights reserved.