如何让Nginx模拟主机宕机?禁止通过公网IP访问站点
问题分析与解决方案
你的猜测完全正确:
- 访问不存在的主机时,客户端发送TCP SYN包后无任何响应,连接无法建立,最终超时判定主机不存在;
- Nginx的
return 444是在TCP三次握手完成后主动关闭连接,客户端仍能感知到服务器存在,和宕机效果差异明显。
要实现“模拟主机宕机”的无响应效果,不能仅依赖Nginx的HTTP层配置——因为Nginx监听端口时,操作系统内核会自动处理TCP握手。必须从网络层面拦截直接IP访问的流量,让服务器彻底不响应这类请求,以下是可行方案:
方案1:用iptables过滤HTTP/HTTPS流量(推荐)
针对HTTP(80端口)
利用iptables的string模块匹配HTTP请求中的Host头,若Host为服务器公网IP,则直接丢弃流量:
# 替换为你的服务器公网IP PUBLIC_IP="x.x.x.x" # 丢弃Host头为公网IP的HTTP请求 iptables -A INPUT -p tcp --dport 80 -m string --algo bm --string "Host: $PUBLIC_IP" -j DROP # 处理带端口的IP访问场景(如x.x.x.x:80) iptables -A INPUT -p tcp --dport 80 -m string --algo bm --string "Host: $PUBLIC_IP:" -j DROP
针对HTTPS(443端口)
HTTPS的Host头加密,但SNI(Server Name Indication)字段是明文的,可通过iptables的tls模块匹配SNI(需内核支持TLS模块):
PUBLIC_IP="x.x.x.x" # 丢弃SNI为公网IP的HTTPS请求 iptables -A INPUT -p tcp --dport 443 -m tls --tls-sni $PUBLIC_IP -j DROP
配置后,直接用IP访问的流量会被彻底丢弃,客户端会因长时间无响应判定主机不存在,和访问无效主机的效果完全一致。
方案2:用tc工具模拟超时(备选)
若iptables的string/tls模块无法使用(如内核版本过低),可通过tc工具给直接IP访问的流量设置极高延迟,让客户端超时:
PUBLIC_IP="x.x.x.x" # 创建根流量队列 tc qdisc add dev eth0 root handle 1: htb default 10 # 创建默认流量类 tc class add dev eth0 parent 1: classid 1:10 htb rate 1000mbit # 匹配Host头为公网IP的HTTP流量,分配到延迟队列 tc filter add dev eth0 parent 1: protocol ip prio 1 u32 \ match ip dport 80 0xffff \ match u8 0x48 0xff at 40 \ # 匹配HTTP请求起始字符'H' match u32 $(printf '0x%08x' $(echo $PUBLIC_IP | awk -F. '{print ($1<<24)+($2<<16)+($3<<8)+$4}')) 0xffffffff at 52 \ # 匹配公网IP的十六进制值 flowid 1:20 # 给目标队列设置10秒延迟 tc qdisc add dev eth0 parent 1:20 netem delay 10000ms
此方法让客户端等待超时,效果接近宕机,但不如iptables DROP彻底。
注意事项
- 配置iptables规则后,需保存规则(如
iptables-save > /etc/iptables/rules.v4),避免服务器重启后失效; - 若使用CDN服务,可直接在CDN面板配置“仅允许域名访问”,隐藏源站IP,这是更简便的方案。
内容的提问来源于stack exchange,提问作者Alpaca0x0
相关产品推荐
相关产品推荐

