如何在Nginx同一端口同时实现SSH、HTTP、HTTPS服务共存?
方案可行性说明
该需求完全可以实现,但原有仅依赖$ssl_preread_protocol的配置无法直接支持三类服务共存:这个变量仅能识别TLS握手的协议版本,无法区分非TLS的SSH和明文HTTP流量,需要搭配Nginx官方的ngx_stream_js_module(njs模块)做流量特征识别即可实现路由分流。
前置要求
- 你的Nginx需要安装
ngx_stream_js_module和ngx_stream_ssl_preread_module两个模块,主流发行版可直接安装对应的预编译包(如Debian/Ubuntu系的nginx-module-njs、nginx-module-stream包),也可以自行编译Nginx时加入对应模块。 - 提前将SSH、HTTPS、HTTP三类服务分别在本地不同端口配置为可正常访问,比如SSH跑在127.0.0.1:22、HTTPS跑在127.0.0.1:8443、HTTP跑在127.0.0.1:8080。
具体配置步骤
- 新建流量特征识别脚本
/etc/nginx/detect_proto.js,内容如下:
function detect(s) { s.on('upload', function (data, flags) { // 首包长度不足时等待更多数据 if (data.length < 3) { return; } // 识别SSH流量:SSH协议首包固定以"SSH-"开头 if (data.startsWith('SSH-')) { s.variables.upstream = '127.0.0.1:22'; s.done(); return; } // 识别明文HTTP流量:匹配常见HTTP请求方法前3位 const http_methods = ['GET', 'POS', 'PUT', 'DEL', 'HEA', 'OPT', 'CON', 'TRA', 'PAT']; if (http_methods.includes(data.slice(0,3))) { s.variables.upstream = '127.0.0.1:8080'; s.done(); return; } // 剩余默认走HTTPS上游 s.variables.upstream = '127.0.0.1:8443'; s.done(); }); } export default {detect};
- 修改Nginx主配置
nginx.conf,先在顶层(events块外部)加载njs模块:
load_module modules/ngx_stream_js_module.so;
- 在
nginx.conf中新增和http块同级的stream块,配置端口复用逻辑:
stream { # 加载自定义流量识别脚本 js_import /etc/nginx/detect_proto.js; js_set $detect_upstream detect_proto.detect; # 开启TCP代理的源IP透传(可选,后端服务需要获取真实客户端IP时配置) proxy_protocol on; server { listen 443 reuseport; ssl_preread on; proxy_pass $detect_upstream; # 超时参数按需调整,SSH场景建议调大超时时间避免断连 proxy_timeout 1h; proxy_connect_timeout 10s; } }
- 配置完成后执行
nginx -t检查语法正确性,确认无报错后执行nginx -s reload重载配置即可生效。
注意事项
- 若你有按TLS版本分流HTTPS的需求,可以在njs识别为HTTPS流量后,结合原有
$ssl_preread_protocol变量做二次路由即可。 - 若业务存在非标准开头的自定义HTTP请求,可自行调整js脚本中的HTTP特征匹配规则,避免识别错误。
- 若后端服务需要获取真实客户端IP,需要对应后端服务配置支持proxy protocol协议解析。
内容的提问来源于stack exchange,提问作者Lonko
相关产品推荐
相关产品推荐

