随着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指南和模块文档,但它似乎没有被很好地引用.如果有人能指出我正确的方向,我将不胜感激.
关于ServerFault的相关问题:反向代理可以使用带SSL的SNI通过吗?
这是现在可以用另外的ngx_stream_ssl_preread模块在Nginx的1.11.5添加和ngx_stream_map模块中添加1.11.2.
这允许Nginx读取TLS客户端Hello并根据要使用的后端的SNI扩展来决定.
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; } }
如果我理解正确,你实际上希望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
,即使指令是关于到底是相同的):
http://nginx.org/docs/stream/ngx_stream_core_module.html
http://nginx.org/docs/stream/ngx_stream_access_module.html
http://nginx.org/docs/stream/ngx_stream_limit_conn_module.html
http://nginx.org/docs/stream/ngx_stream_proxy_module.html
http://nginx.org/docs/stream/ngx_stream_ssl_module.html
http://nginx.org/docs/stream/ngx_stream_upstream_module.html
请注意,每个模块中的每个nginx指令都具有有限数量的适用指令Context
.
因此,遗憾的是,这里根本没有指示窥探SNI!
相反,它实际上记录在stream_core
引用中," Different servers must listen on different address:port pairs.
",正如您可能注意到的那样,这也违背了该listen
指令在更常见的情况下的工作方式http_core
,并且是一个相当明确的参考指出这一事实. SNI支持目前正在为listen
内部实施stream
.
作为讨论点和解决方案的建议,OpenVPN流量只是具有可窥探SNI的TLS的假设也不一定正确(但我不太熟悉OpenSSL或SNI):
考虑到即使SNI今天被动地窥探,这显然违背了TLS保证连接安全的承诺,因此,可能会在未来版本的TLS中发生变化.
为了讨论的缘故,如果OpenVPN的是只使用一个TLS连接,如果它不使用TLS验证用户的身份用户证书(这将使它更难以MITM流,但仍然承载认证数据都一起)那么,理论上,如果nginx确实在listen
内部有SNI支持stream
,那么你可能已经能够使用nginx主动MitM它(因为proxy_ssl
已经支持stream_proxy
).
最重要的是,我认为OpenVPN可能最好通过自己的基于UDP的协议运行,在这种情况下,您可以使用相同的IP地址和端口号作为基于TCP的https的一个实例和另一个基于UDP的OpenVPN没有冲突.
最后,您可能会问,流模块对于什么有用呢?我相信它的目标受众是,(0),基于客户端的IP地址,负载均衡HTTP/2
多个upstream
服务器hash
,和/或,(1),更直接和协议无关的替代stunnel
.
如@Lochnair所述,您可以使用ngx_stream_map模块和$ server_addr变量来解决此问题。这是我的例子。
我的主机IP是192.168.168.22
,我使用keepalived绑定2虚拟IP来eth0
。
$sudo ip a ... 2: eth0:mtu 1500 qdisc mq state UP qlen 1000 link/ether 5c:f3:fc:b9:f0:84 brd ff:ff:ff:ff:ff:ff inet 192.168.168.22/24 brd 192.168.168.255 scope global eth0 valid_lft forever preferred_lft forever inet 192.168.168.238/32 scope global eth0 valid_lft forever preferred_lft forever inet 192.168.168.239/32 scope global eth0 valid_lft forever preferred_lft forever $nginx -v nginx version: nginx/1.13.2 $cat /etc/nginx/nginx.conf ... stream { upstream pod53{ server 10.1.5.3:3306; } upstream pod54{ server 10.1.5.4:3306; } map $server_addr $x { 192.168.168.238 pod53; 192.168.168.239 pod54; } server { listen 3306; proxy_pass $x; } }
因此,我可以通过不同的VIP使用相同的端口3306访问不同的MySQL服务。就像通过diffrent使用同一端口访问不同的HTTP服务一样server_name
。
192.168.168.238 -> 10.1.5.3 192.168.168.239 -> 10.1.5.4