Nginx Stream层HTTPS透传场景下基于主机名的IP访问限制配置咨询
Nginx Stream层HTTPS透传场景下基于主机名的IP访问限制配置咨询
兄弟,我明白你现在的困惑——用ssl_preread做Stream层HTTPS透传的时候,想针对不同主机名限制特定IP段,确实不像HTTP层那样直接用host和allow/deny那么直观。不过咱们可以通过Nginx的geo和map模块结合起来实现,我给你捋清楚步骤和配置示例:
核心思路
因为是Stream层透传,没法直接解析HTTP请求头里的Host字段,所以得靠ssl_preread读取TLS握手阶段的SNI(服务器名称指示)字段,也就是客户端请求的主机名。然后结合geo模块定义IP限制规则,再用map把主机名和对应的IP规则关联起来,最后在Stream服务块里判断是否拒绝访问。
具体配置示例
stream { # 定义针对host1的IP黑名单:10.0.1.0/24段的IP标记为需要拦截 geo $host1_blocked { default 0; 10.0.1.0/24 1; } # 定义针对host2的IP黑名单:10.0.44.0/24段的IP标记为需要拦截 geo $host2_blocked { default 0; 10.0.44.0/24 1; } # 根据SNI(客户端请求的主机名)匹配对应的IP拦截规则 map $ssl_preread_server_name $block_access { host1 $host1_blocked; host2 $host2_blocked; default 0; # 其他主机名不做IP限制 } server { listen 443; ssl_preread on; # 必须开启这个才能读取SNI # 如果标记为需要拦截,直接关闭连接(return 444是Nginx特有的无响应关闭) if ($block_access = 1) { return 444; } # 这里放你原本的上游转发配置,比如根据SNI转发到不同上游 # 举个例子,如果你原本就有根据SNI匹配上游的map: # map $ssl_preread_server_name $upstream { # host1 upstream_host1; # host2 upstream_host2; # } # proxy_pass $upstream; } # 如果你有单独的上游定义,放在这里 # upstream upstream_host1 { # server 192.168.1.10:443; # } # upstream upstream_host2 { # server 192.168.1.20:443; # } }
关键细节说明
geo模块用来定义IP段的匹配规则,匹配到的IP会返回1,其他返回0,这样我们就能标记哪些IP需要被拦截。map模块把SNI($ssl_preread_server_name)和对应的geo规则绑定,比如当客户端请求的是host1时,就用host1的IP黑名单规则。return 444是比较隐蔽的拦截方式,Nginx会直接关闭连接,不会给客户端返回任何错误信息,避免泄露服务器配置细节;如果你需要返回明确的错误,也可以用return 503之类的,但Stream层的错误码不像HTTP层那么直观。- 注意
ssl_preread on必须开启,否则读不到SNI字段,整个规则就失效了。
备注:内容来源于stack exchange,提问作者Caesar




