用Nginx侦听同端口的TCP应用和HTTP应用
建站的人,必定会使用到的一个工具——Nginx,大家或多或少都了解Nginx的一些特性,比如用作负载均衡服务器,再比如更常见的——在同一台主机上挂载好几个App,然后通过Nginx来匹配分流。

大部分时候,我们写Nginx配置时都是这样的,例如:
server {
listen 443;
server_name a.com;
...
}
server {
listen 443;
server_name b.com;
...
}
server {
listen 443;
server_name c.com;
...
}
不是说同一个端口只能由一个程序使用吗,为什么这里监听了3个程序,Nginx还能正常工作?
其实我们在使用Nginx时,大部分时候是使用了它的http模块,而上面的三个
http {
server {...}
server {...}
server {...}
}
而
stream模块分流
而如果我们只是单纯的想要转发TCP流量(它可能也是HTTP流量)到下级应用时,那么使用http模块就无法满足我们的要求,就需要添加stream模块支持到Nginx中,通常它在Nginx中是默认不开启的,需要手动在 /path/to/nginx.conf 中添加以下配置:
# nginx.conf
load_module /usr/lib/nginx/modules/ngx_stream_module.so;
...
include /etc/nginx/stream-enabled/*;
这样就启用了stream模块,stream模块的工作方式可参考下图:

它的工作模式和http模块很相似,也是通过侦听端口+SNI匹配的形式来完成应用的分流。但是注意,stream模块和http模块不能侦听同一个端口,这两个模块应该被看作是互相独立的应用,也就是说,上图中通过stream模块进行监听了443端口,那么http模块就无法再监听443端口了,但是对于浏览器前端而言,他们仍可通过443端口访问到位于http模块下挂载的app(a.com)
一个stream配置的例子:
stream {
#sni match
map $ssl_preread_server_name $backend_name {
a.com http_app;
d.com tcp_app;
# 域名都不匹配情况下的默认值
default web;
}
upstream http_app {
server 127.0.0.1:1443;
}
upstream tcp_app {
server 127.0.0.1:14443;
}
upsteam web {
server 127.0.0.1:80;
}
server {
listen 443 reuseport;
listen [::]:443 reuseport;
proxy_pass $backend_name;
ssl_preread on;
}
}