排查 nginx 多个 server_name 冲突,核心在于理解其优先级匹配规则:精确匹配最高,通配符次之,正则表达式最低。解决冲突需确保配置文件中没有重复的 server_name 定义,并检查是否存在未明确指定的默认请求处理逻辑。

如何确定哪个 server 块处理了特定域名请求
当多个 server 块包含相同的 server_name 时,Nginx 会依据精确度、通配符和正则表达式的优先级来选择最匹配的块。如果所有 server_name 都不匹配,则请求会被路由到该端口上配置的默认 server 块(即带有 default_server 参数的块)。

server {
listen 80 default_server;
server_name example.com www.example.com;
root /var/www/example;
}
server {
listen 80;
server_name *.example.com;
root /var/www/subdomains;
}
server {
listen 80;
server_name ~^test\.(.*)$;
root /var/www/test;
}
在上述配置中,访问 www.example.com 将命中第一个块,因为它是精确匹配。访问 sub.example.com 将命中第二个块,因为它是通配符匹配。访问 test.anything 将命中第三个块,因为它是正则匹配。若访问 unknown.com,由于不匹配任何 server_name,它将回退到带有 default_server 的第一个块。
如何处理未指定 server_name 的默认请求
对于未明确指定 server_name 的请求,Nginx 的行为取决于是否配置了 default_server。如果没有显式设置 default_server,Nginx 会选择监听该端口的第一个 server 块作为默认处理者。这可能导致意外流量被错误地路由到非预期的站点。

server {
listen 80;
# 没有 server_name,也没有 default_server
root /var/www/default;
}
server {
listen 80 default_server;
server_name _;
root /var/www/secure-default;
}
在上面的例子中,尽管第一个 server 块先出现,但由于第二个块明确声明了 default_server,所有未匹配其他 server_name 的请求都会被路由到第二个块。建议始终为每个监听端口显式定义一个 default_server,以避免不可预测的行为。
基于具体输入 test.conf 的冲突验证
为了验证上述理论,我们创建一个具体的配置文件 test.conf 并模拟不同域名的请求。假设我们有以下配置:
server {
listen 80;
server_name app.test.com;
return 200 "App Server";
}
server {
listen 80;
server_name *.test.com;
return 200 "Wildcard Server";
}
server {
listen 80;
server_name ~^(.*)\.test\.com$;
return 200 "Regex Server";
}
使用 curl -H "Host: app.test.com" http://localhost 测试,预期返回 "App Server",因为精确匹配优先级最高。使用 curl -H "Host: sub.test.com" http://localhost 测试,预期返回 "Wildcard Server",因为通配符匹配优于正则。使用 curl -H "Host: deep.sub.test.com" http://localhost 测试,预期返回 "Regex Server",因为通配符 *.test.com 无法匹配三级子域名,而正则表达式可以。这些测试结果证实了 Nginx 的匹配优先级机制。


















