我目前正在使用以下(简化)配置通过同一端口代理 http 和 https 连接(aws elastic beanstalk 需要):
server {
listen 777 ssl;
server_name foo.com;
ssl_certificate /etc/nginx/ssl/foo.crt;
ssl_certificate_key /etc/nginx/ssl/foo;
root /usr/share/nginx/www;
index index.html index.htm;
error_page 418 = @upstream;
error_page 497 = @upstream;
location / {
return 418;
}
location @upstream {
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
proxy_pass http://127.0.0.1:8080;
}
}
我想将上游更改为 uwsgi 并让 uwsgi 处理 ssl,因为它可以简化部署。
如何调整我的配置以适用于 SNI HTTPS 和 HTTP,而无需 Nginx 解密 SSL 流量?
答案1
不,您无法使用 Nginx 来实现。默认情况下,Nginx 始终解密内容,因此 Nginx 可以应用请求路由。可以尝试以下解决方案:
有第三方模块称为nginx_tcp_proxy_模块。我还没试过。因为那个模块在网络层做代理,所以它会传递请求而不解密。
首选解决方案是使用 HAProxy。本教程建议您可以使用具有 SNI 功能的 TCP 代理。
边注
默认情况下,Nginx 始终在代理上充当 SSL 卸载/解密进程。以下是执行 SSL 卸载的一些优势(取自这里)
- 提高性能
- 更好地利用后端服务器
- 智能路由
- 证书管理
- 安全补丁程序
答案2
看起来现在支持使用ngx_stream_ssl_preread_module模块
答案3
执行此操作时需要注意以下几点:
- 您将必须使用
stream
块而不是http
块,这意味着: - 您无法设置
error_page
指令,因为 HTTP 错误代码位于应用层,而您无法解密该层 - 您无法
proxy_pass
连接到http://
服务器,因为您不再进行 SSL 终止 - 你不能,
proxy_set_header
因为你不能将纯文本注入加密流中
如果您接受这些限制,例如,您将在另一台服务器(作为最终目的地或执行 SSL 终止的中间代理)上进行工作,那么您需要执行以下操作:
首先,请注意,大多数 nginx 服务器配置都会自动将所有内容包装在一个
http
块中。因此,如果您习惯于/etc/nginx/conf.d
在 Red Hat 类型的安装中直接放入文件,或者在 Debian 类型的安装/etc/nginx/sites-available
中使用符号链接/etc/nginx/sites-enabled
,那么这在这里行不通。您必须对根配置文件进行至少一些小的更改/etc/nginx.conf
,即使只是为了创建一个包含其他文件的流块,如下所示:stream { include /etc/nginx/stream.d/*.conf; }
接下来,您需要创建一个流服务器。您只能使用模块中的指令
ngx_stream_*
,这些指令不包括所有特定于 HTTP 的内容。正如 Robert Wagner 的回答所指出的那样,您需要使用ngx_stream_ssl_preread
1.11.5 之前的 nginx 版本中不存在的模块。.conf
在/etc/nginx/stream.d
或您选择的任何其他目录中创建一个扩展名为 的文件,并定义您的服务器。以下内容逐字摘自模块文档中的内容,并给出了基于 SNI 的过滤示例(还有可用的 ALPN 和 SSL 版本过滤):map $ssl_preread_server_name $name { backend.example.com backend; default backend2; } upstream backend { server 192.168.0.1:12345; server 192.168.0.2:12345; } upstream backend2 { server 192.168.0.3:12345; server 192.168.0.4:12345; } server { listen 12346; proxy_pass $name; ssl_preread on; }
现在,您有一台服务器,它不会解密流量,但会根据 SNI 确定将其发送到何处。如果客户端连接并发出请求,
backend.example.com
则它将被路由到backend
,否则它将被路由到backend2
。
您可能还需要考虑其他事项,例如设置tcp_nodelay
或定义流log_format
并启用access_log
块stream
,但格式和变量当然与 HTTP 访问日志不同。