Nginx 在 TCP/TLS 下通过 域名 / SNI 分流的几种方式
总之,迁移博客的计划正在日程上了。
问题
关于自建站点总是有几个很现实的问题。
例如我又想做图站、又想做博客、又想进行科学研究,我又想给每个图站和博客都单独配一个域名而不是路径(路径太长了不是吗?),但你只有一个服务器。
所以通过 HTTP 请求中的域名或者 TLS 中的 SNI 对流量进行分流就是个必要的课题。
通过域名分流的几种方案
现在基本所有的网页服务器标配 TLS 。所以就有以下两个分支选项出现:
- Plan A: 某个前置软件负责 TLS 并处理分流(例如 Xray-core 的 fallback),然后把 TCP 丢给 Nginx 继续处理分流。
- Plan B: Nginx 负责 TLS 并处理分流,然后把流量原封不动地丢给上游进行处理。
理论上,方案 B 更具有可扩展性和可维护性,但如果某个前置软件声明“它们处理分流的效率更高”,或者你已经是方案 A 的模样却不想改到方案 B,则你也可以使用方案 A。
方案 A
既然丢给 Nginx 的已经是纯粹的 TCP 流量,那么流量包含的应该就是普通的 HTTP 请求。
如果你只是想把流量丢给几个网页服务器,按照如下方式配置即可:
server {
listen 80;
server_name _;
return 301 https://$host$request_uri;
} # HTTPS 永久重定向
server {
listen 11451; # 如果你开了 proxy_protocol 则往后面追加 proxy_protocol,h2同理
server_name A.com B.com;
....
}
server {
listen 11451;
server_name C.com D.com;
....
}
如果你说,不,我想把 TCP 流量中包含的 HTTP Host Header 给取出来,然后再通过这个 Host 在 Nginx 的 Stream Proxy 中进行分流,那你可以参考 这篇文章 ,因为我没试过。
方案 B
如果是 Nginx 来处理 TLS 的话可能会更复杂。
配置如下:
stream {
map $ssl_preread_server_name $name {
a.x.com a;
b.x.com b;
}
upstream a {
server 127.0.0.1:114;
}
upstream b {
server 127.0.0.1:514;
}
server {
listen 10.0.0.1:443;
proxy_pass $name;
ssl_preread on;
# proxy_protocol on;
}
}
http {
...
server {
listen 127.0.0.1:114;
server_name a.x.com;
...
}
server {
listen 127.0.0.1:514;
server_name b.x.com;
...
}
}
其中,ssl_preread on;
会允许 Nginx 读取 TLS 握手过程开始时的 SNI(即变量 $ssl_preread_server_name
)并通过这个变量来进行上游的分流。但实际使用如上的配置可能会产生额外的问题。对这一方案的更详细的配置请参考 Xiaomage's Blog - 使用 Nginx 进行 SNI 分流并完美和网站共存。
引用 / 扩展阅读
https://stackoverflow.com/questions/34741571/nginx-tcp-forwarding-based-on-hostname
https://serverfault.com/questions/1015880/extracting-http-host-header-from-nginx-stream-proxy
http://nginx.org/en/docs/http/server_names.html
Xiaomage's Blog - 使用 Nginx 进行 SNI 分流并完美和网站共存
本文链接:https://pst.iorinn.moe/archives/nginx-sni-redirect.html
许可: https://pst.iorinn.moe/license.html若无特别说明,博客内的文章默认将采用 CC BY 4.0 许可协议 进行许可☆