nginx实现一个对外端口同时支持http和https协议访问
前言
- 最近有一个需求,需要让一个非80端口的http服务支持https访问;但是业务牵扯太多没法将http直接改为https,因此需要一个端口同时支持http和https
方案一. 使用nginx的stream、 stream_ssl_preread模块
参考资料
1.准备工作
- nginx版本1.11.5及以上
- 由于stream和stream_ssl_preread模块非默认引入,需要在编译安装nginx时引入;编译时添加配置参数 --with-stream --with-stream_ssl_preread_module
- 这里给一个笔者编译tengine时的配置,仅供参考
./configure --add-module=./modules/ngx_http_upstream_vnswrr_module --add-module=./modules/ngx_http_proxy_connect_module --without-http_rewrite_module --with-openssl=/root/openssl-1.0.1j --with-pcre --without-http_gzip_module --with-stream --with-stream_ssl_preread_module --with-stream_ssl_module --with-stream_sni
2.配置stream
stream {
upstream http_gateway {
# 20036端口是一个开启http的端口
server 127.0.0.1:20036;
}
upstream https_gateway {
# 20037端口是一个开启https的端口
server 127.0.0.1:20037;
}
# 根据不同的协议走不同的upstream
map $ssl_preread_protocol $upstream{
default http_gateway;
"TLSv1.0" https_gateway;
"TLSv1.1" https_gateway;
"TLSv1.2" https_gateway;
"TLSv1.3" https_gateway;
}
server {
listen 12345;
ssl_preread on;
proxy_pass $upstream;
}
}
3.简单的nginx.conf示例供参考
user root;
worker_processes 2;
worker_rlimit_nofile 100000;
stream {
upstream http_gateway {
server 127.0.0.1:20036;
}
upstream https_gateway {
server 127.0.0.1:20037;
}
map $ssl_preread_protocol $upstream{
default http_gateway;
"TLSv1.0" https_gateway;
"TLSv1.1" https_gateway;
"TLSv1.2" https_gateway;
"TLSv1.3" https_gateway;
}
server {
listen 12345;
ssl_preread on;
proxy_pass $upstream;
}
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
upstream gateway_service{
server 127.0.0.1:8080 weight=1;
server 127.0.0.1:8081 weight=2;
}
server {
listen 20036;
listen 20037 ssl;
server_name xxx.com;
ssl_certificate xxx.pem;
ssl_certificate_key xxx.key;
location / {
proxy_pass http://gateway_service;
}
}
}
上面配置即可实现端口12345同时支持http和https协议访问。
但是上面配置存在一个弊端就是服务端无法获取到客户端请求的真实ip地址,因为使用stream之后,上面配置无法获取到客户端的真实ip。
于是对上面配置进行进一步修改,
user root;
worker_processes 2;
worker_rlimit_nofile 100000;
stream {
upstream http_gateway {
server 127.0.0.1:20036;
}
upstream https_gateway {
server 127.0.0.1:20037;
}
map $ssl_preread_protocol $upstream{
default http_gateway;
"TLSv1.0" https_gateway;
"TLSv1.1" https_gateway;
"TLSv1.2" https_gateway;
"TLSv1.3" https_gateway;
}
server {
listen 12345;
ssl_preread on;
proxy_pass $upstream;
proxy_protocol on; #开启protocol
}
}
http {
real_ip_recursive on;
real_ip_header proxy_protocol; #基于stream层传来protocol数据进行后续修改
set_real_ip_from 127.0.0.0/24; #从real_ip_header中删除这个ip段的ip,也可直接写具体ip;
include mime.types;
default_type application/octet-stream;
sendfile on;
upstream gateway_service{
server 127.0.0.1:8080 weight=1;
server 127.0.0.1:8081 weight=2;
}
server {
listen 20036;
listen 20037 ssl;
server_name xxx.com;
ssl_certificate xxx.pem;
ssl_certificate_key xxx.key;
location / {
proxy_pass http://gateway_service;
}
}
}
上面配置即可实现将客户端ip透传
参考文章: