Nginx SSL预读无法从SSH连接提取服务器名的问题与解决
Nginx配置SSL预读实现SSH按服务器名路由失败的解决方法
问题场景
尝试通过Nginx的SSL预读功能,根据服务器名将入站SSH连接路由至不同上游节点,但连接被拒绝,且Nginx无法提取服务器名。已确认Nginx编译时包含--with-stream和--with-stream-ssl-preread-module模块,配置无语法错误:
stream { log_format ssh '|| SSL_PreRead $ssl_preread_server_name ||'; access_log /opt/homebrew/var/log/nginx/ssh_access.log ssh; map $ssl_preread_server_name $ssh_upstream { app1.mydomain.com app1-deviceIP:22; app2.mydomain.com app2-deviceIP:22; app3.mydomain.com app3-deviceIP:22; app4.mydomain.com app4-deviceIP:22; app5.mydomain.com app5-deviceIP:22; app6.mydomain.com app6-deviceIP:22; app7.mydomain.com app7-deviceIP:22; app8.mydomain.com app8-deviceIP:22; app9.mydomain.com app9-deviceIP:22; } server { listen 22000; # 网络路由器将入站22端口流量转发至Nginx的22000端口 proxy_pass $ssh_upstream; ssl_preread on; } }
多次尝试连接后,ssh_access.log中$ssl_preread_server_name变量为空:
|| SSL_PreRead - || || SSL_PreRead - || || SSL_PreRead - || || SSL_PreRead - || || SSL_PreRead - || || SSL_PreRead - ||
使用的连接命令:
ssh -i my_private_key_file username@app1.mydomain.com
问题原因与解决方案
问题原因
SSH本身不支持SSL的Server Name Indication(SNI)机制,直接发起SSH连接无法携带SNI信息,导致Nginx无法通过$ssl_preread_server_name提取服务器名。
解决方案
需要将SSH封装在SSL连接中并携带SNI,同时修改Nginx配置终止SSL连接,通过$ssl_server_name识别服务器名并路由。
1. 客户端连接命令修改
使用如下命令发起封装了SSL的SSH连接:
ssh -o ProxyCommand="openssl s_client -quiet -servername app1.mydomain.com -connect MyNginxServer:22000" app1_username@app1.mydomain.com -i ssh_private_key_file
2. Nginx配置修改
修改后的Stream配置如下,需配置SSL证书以终止SSL连接:
stream { log_format ssh '|| SSL_ServerName $ssl_server_name || Upstream $ssh_upstream ||'; access_log /opt/homebrew/var/log/nginx/ssh_access.log ssh; map $ssl_server_name $ssh_upstream { app1.mydomain.com app1-deviceIP:22; app2.mydomain.com app2-deviceIP:22; app3.mydomain.com app3-deviceIP:22; app4.mydomain.com app4-deviceIP:22; app5.mydomain.com app5-deviceIP:22; app6.mydomain.com app6-deviceIP:22; app7.mydomain.com app7-deviceIP:22; app8.mydomain.com app8-deviceIP:22; app9.mydomain.com app9-deviceIP:22; } server { listen 22000 ssl; # 网络路由器将入站22端口流量转发至Nginx的22000端口 ssl_certificate /myPath/fullchain.pem; ssl_certificate_key /myPath/privkey.pem; proxy_pass $ssh_upstream; } }
注意事项
直接映射服务器名到上游IP并非最佳实践,建议参考Nginx文档定义上游组。
内容的提问来源于stack exchange,提问作者Junto026
相关产品推荐
相关产品推荐

