Linux-Nginx同一端口同时支持HTTP、HTTPS协议
要在 同一个端口(8081)同时支持 HTTP 和 HTTPS 协议,标准的 Nginx http 模块是无法直接实现的(因为 listen 8081; 和 listen 8081 ssl; 不能同时生效且会冲突)。
标准解决方案是使用 Nginx 的 stream 模块配合 ssl_preread 功能,在 TCP 层(四层)识别流量类型,然后将 HTTPS 流量转发到内部 SSL 端口,将 HTTP 流量转发到内部普通 HTTP 端口,从而对外只暴露 8081 端口。
以下是详细的解决方案和操作步骤:
一、 环境检查
首先确认你的 Nginx 是否支持 stream 和 ssl_preread 模块:
nginx -V 2>&1 | grep -E 'with-stream|ssl_preread'
如果输出中包含 --with-stream 和 --with-stream_ssl_preread_module 则可以支持。如果没有,需要安装 nginx-module-stream 或重新编译 Nginx。
二、 准备 SSL 证书
如果还没有证书,可以生成自签名证书(生产环境请使用正规 CA 证书):
mkdir -p /home/test/nginx/ssl
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
-keyout /home/test/nginx/ssl/8081.key \
-out /home/test/nginx/ssl/8081.crt \
-subj "/C=CN/ST=Beijing/L=Beijing/O=MyOrg/CN=192.168.0.3"
三、 配置 Stream 端口复用(核心)
编辑 Nginx 主配置文件 /home/test/nginx/conf/nginx.conf(与 http 块平级,不要写在 http 里面):
# 在 http {} 块之外添加 stream 块
stream {
# 通过 ssl_preread 识别协议,分发到不同的内部后端
map $ssl_preread_protocol $backend {
default 127.0.0.1:18081; # 非SSL(HTTP) -> 内部HTTP端口
"~^TLSv" 127.0.0.1:18082; # SSL/TLS(HTTPS) -> 内部HTTPS端口
}
server {
listen 8081; # 对外暴露的端口,保持不变
ssl_preread on; # 开启SSL预读
proxy_pass $backend; # 按协议转发
proxy_connect_timeout 600s;
proxy_timeout 600s;
}
}
http {
include /home/test/nginx/conf.d/*.conf;
# ... 你原有的 http 配置 ...
}
四、 调整 conf.d 下的配置文件
现在需要将原来的 8081 配置拆分为内部 HTTP 和内部 HTTPS 两个服务。
1. 修改原有的 xgxjk_8081.conf(改为内部 HTTP 端口 18081)
# /home/test/nginx/conf.d/xgxjk_8081.conf
server {
listen 18081; # 改为内部端口,由 stream 转发过来
server_name 192.168.0.3;
# 保留你原有的代理配置
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto http;
proxy_set_header X-NginX-Proxy true;
proxy_connect_timeout 600s;
proxy_read_timeout 600s;
proxy_send_timeout 600s;
client_max_body_size 2000M;
client_body_buffer_size 2000M;
# 以下是你原有的 location 配置,原样保留
location /webtest {
proxy_pass http://192.168.0.6:8082/webtest;
}
}
2. 新建 HTTPS 配置文件(内部端口 18082)
# /home/test/nginx/conf.d/xgxjk_8081_ssl.conf
server {
listen 18082 ssl; # 内部 SSL 端口
server_name 192.168.0.3;
# SSL 证书配置
ssl_certificate /home/test/nginx/ssl/8081.crt;
ssl_certificate_key /home/test/nginx/ssl/8081.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
# 代理头信息(注意 X-Forwarded-Proto 改为 https)
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-NginX-Proxy true;
proxy_connect_timeout 600s;
proxy_read_timeout 600s;
proxy_send_timeout 600s;
client_max_body_size 2000M;
client_body_buffer_size 2000M;
# 复用相同的 location 规则
location /webtest {
proxy_pass http://192.168.0.6:8082/webtest;
}
}
(注:如果 location 很多,建议把 location 部分抽成一个单独文件,用 include 引入,避免重复维护。)
五、 检查并生效配置
# 检查配置文件语法
nginx -t
# 如果语法 OK,重载 Nginx
nginx -s reload
六、 验证
使用 curl 测试端口 8081 是否同时支持两种协议:
# 测试 HTTP
curl -v http://192.168.0.3:8081/cm/
# 测试 HTTPS(忽略证书校验)
curl -v -k https://192.168.0.3:8081/cm/
如果两者都能正常返回后端数据(或你贴出的“资源解析服务请求失败”是后端业务返回,说明通路已通),说明配置成功。
常见问题说明
1. 后端获取真实 IP:因为经过了 stream 转发,后端看到的直接连接是 127.0.0.1。如果需要真实客户端 IP,可以在 HTTP 层通过 X-Real-IP 和 X-Forwarded-For 获取(上述配置已包含)。
2. Nginx 版本过低:如果系统自带 Nginx 版本太老(如 1.12 以下),可能没有 ssl_preread。建议升级到 1.15.0 以上版本,或使用 yum/apt 安装 nginx-all-modules。
3. 防火墙:确保 8081 端口在防火墙中已开放。
按照以上步骤操作,即可实现 8081 端口同时支持 HTTP 和 HTTPS,且对外端口号完全不变。

浙公网安备 33010602011771号