Nginx无法直接用server_name正则“排除”域名,需通过高优先级正则server拦截目标域名并返回444/301,再由default_server兜底处理其余请求。

在 Nginx 中,无法直接用 server_name 的正则表达式“排除”某个域名,但可以通过匹配优先级和逻辑绕过实现等效效果——核心思路是:先用精确或正则匹配要拦截的域名并返回 444 或 301,再用通配或默认 server 处理其余请求。
理解 server_name 匹配顺序是关键
Nginx 按以下优先级匹配 server_name:
- 精确匹配(如
server_name example.com;) - 最长前缀匹配(如
server_name *.example.com;) - 正则匹配(以
~或~*开头,按配置文件中出现顺序) - 默认 server(带
default_server标志,或第一个 server)
因此,“排除”不是靠单个 server 实现,而是靠**显式拦截 + 默认兜底**。
用正则 server 拦截特定域名(推荐做法)
在 http 块中,**提前定义一个正则 server,专门处理需排除的域名**:
server {
listen 80;
server_name ~^(bad-domain\.com|evil-site\.org|.*\.malware\.io)$;
return 444; # 立即关闭连接,不发响应
# 或用 return 301 https://safe.example.com/; 实现重定向
}注意:
- 使用 ~ 表示区分大小写的正则,~* 不区分大小写
- 正则开头加 ^、结尾加 $ 防止误匹配(如避免 bad-domain.com.hacker.net 被捕获)
- 此 server 必须放在其他泛用 server(如 server_name _; 或 server_name *.example.com;)之前,否则可能被跳过
设置默认 server 接管其余所有请求
在拦截 server 之后,定义一个“兜底” server,监听所有未被前面规则捕获的请求:
server {
listen 80 default_server;
server_name _; # 匹配任意未被其他 server 捕获的 Host
root /var/www/default;
index index.html;
}这个 default_server 会处理除 bad-domain.com 等之外的所有域名访问。它不会响应被正则 server 明确拦截的请求——因为那些请求已在上一步终止。
HTTPS 场景下同样适用,但需注意 SNI
对于 HTTPS,Nginx 依赖客户端通过 SNI 扩展发送目标域名。只要客户端支持 SNI(现代浏览器均支持),上述正则 server_name 规则在 listen 443 ssl 块中完全生效:
server {
listen 443 ssl http2;
server_name ~^(test\.dev|staging\..*)$;
ssl_certificate /path/to/wildcard.pem;
ssl_certificate_key /path/to/key.pem;
return 403; # 或 return 302 /maintenance;
}
<p>server {
listen 443 ssl http2 default_server;
server<em>name </em>;
ssl_certificate /path/to/default.pem;
ssl_certificate_key /path/to/default.key;</p><h1>正常业务配置...</h1><p>}⚠️ 注意:若使用自签名证书或未覆盖全部域名的证书,部分旧客户端可能报证书错误——这不是匹配问题,而是 TLS 层限制。

















