![通过 NGINX 代理将下游服务器的 HTTPS 证书传递到客户端](https://linux22.com/image/772459/%E9%80%9A%E8%BF%87%20NGINX%20%E4%BB%A3%E7%90%86%E5%B0%86%E4%B8%8B%E6%B8%B8%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%9A%84%20HTTPS%20%E8%AF%81%E4%B9%A6%E4%BC%A0%E9%80%92%E5%88%B0%E5%AE%A2%E6%88%B7%E7%AB%AF.png)
我有一组 Ubuntu 边缘计算机,它们托管简单的 Web HMI 服务器。许多计算机都位于动态 IP 后面,无法进行端口转发。
因此,为了访问它们,每个服务器都使用 autossh 创建到中央云代理服务器的反向隧道。然后我可以使用以下命令访问每个服务器https://proxy.mydomain.com:6001、6002 等。这是有效的。
我现在想使用 NGINX,这样我们就不必记住端口号了。因此,每个设施都有自己的子域:https://site1.mydomain.com、site2 等。所有子域名都将指向我的代理服务器。然后 NGINX 应该查看子域名,并将 https 流量代理到适当的反向隧道端口。
NGINX 配置如下所示。
我现在的问题是 NGINX 要求我定义 SSL 证书。但是,我想使用已安装在每台边缘计算机上的证书。
那么,我该如何通过 NGINX 代理将这些证书传递给客户端?
如果这不可能——那么在代理服务器上定义一个或单独的证书以用于所有子域的最佳方法是什么?
server {
listen 443 ssl;
server_name site1.mydomain.com;
location / {
proxy_set_header Host $host;
proxy_pass https://127.0.0.1:6001;
proxy_ssl_server_name on;
proxy_redirect off;
}
}
server {
listen 443 ssl;
server_name site2.mydomain.com;
location / {
proxy_set_header Host $host;
proxy_pass https://127.0.0.1:6002;
proxy_ssl_server_name on;
proxy_redirect off;
}
}
更新 对于那些好奇的人,我能够使用“SNIProxy”项目代替 NGINX 并解决这个问题。HTTPS 证书毫无问题地通过了。
答案1
您可以为您的代理使用通配符证书*.mydomain.com
。
此私钥 + 证书适用于任何子域。
可以从 let's encrypt (certbot) 免费获取,也可以从 digicert 等 CA 付费获取。
答案2
您可以使用该stream
模块将 TLS 协议按原样传递给客户端。
我自己没有使用过这种配置,所以它可能不是 100% 准确,但应该可以展示出其原理。
stream {
listen 443;
ssl_preread on;
proxy_connect_timeout 1s;
proxy_timeout 3s;
proxy_pass $upstream;
}
map $ssl_preread_server_name $upstream {
site1.example.com 127.0.0.1:6001;
site2.example.com 127.0.0.2:6002;
default site1;
}
在stream
代码块中,我们启用了 SSL 协议数据的预读取。Nginx 将 SNI 字段提取到$ssl_preread_server_name
变量中。
我们使用map
功能将预读的服务器名称转换为目标。然后该目标被用作stream
模块proxy_pass
目标。
这里 nginx 仅读取 SSL 连接的主机名,然后将 TCP 连接代理到该主机名的目的地。
答案3
将其放到 nginx.conf 的根目录并确保已安装 nginx 流模块(例如yum install nginx-mod-stream
:)
stream {
server {
listen 443;
ssl_preread on;
proxy_connect_timeout 1s;
proxy_timeout 3s;
proxy_pass $upstream;
}
upstream site1 {
server https://127.0.0.1:6001;
}
upstream site2 {
server https://127.0.0.1:6002;
}
map $ssl_preread_server_name $upstream {
www.domain1.online site1;
www.domain2.online site2;
default site1;
}
}