域名访问Nginx出现默认页或错误站点,排查方向往往不是DNS没生效,而是Nginx的server_name没有匹配到请求里的Host头。Nginx本身并不负责把域名解析成IP,这个动作由DNS完成;Nginx的职责是在同一个IP和端口上,根据HTTP请求头中的Host字段,把流量分发给不同的虚拟主机。理解这两层机制,配置才不会跑偏。

一、先区分DNS解析和Nginx的server_name匹配
域名从输入到访问Nginx,通常先经过DNS解析,把www.ipipp.com转换成服务器公网IP。Nginx监听80或443端口后,收到请求时会读取HTTP请求头里的Host字段。这个字段的值就是浏览器地址栏里的域名。Nginx根据Host字段和所有server块中的server_name做匹配,决定由哪个server块处理请求。
server_name支持精确名称、通配符和正则表达式。匹配顺序有明确优先级:先找精确名称,再找以星号开头的起始通配符,比如*.ipipp.com,接着找以星号结尾的末尾通配符,比如www.example.*,最后才尝试正则匹配。如果全部都没匹配上,Nginx会交给默认server处理;没有显式指定default_server时,就使用配置文件中第一个server块。
实际配置中,可以为同一个server_name写多个域名,也可以混用通配符和正则。一个常见的多域名写法如下:
server {
listen 80;
server_name www.ipipp.com ipipp.com;
location / {
root /var/www/example;
index index.html;
}
}
如果要让所有子域名都进入同一个站点,可以使用通配符:
server {
listen 80;
server_name *.ipipp.com;
location / {
root /var/www/wildcard;
}
}
注意通配符server_name只能匹配一级子域名,也就是说*.ipipp.com能匹配a.ipipp.com,但不能匹配a.b.ipipp.com。如果需要多级子域名,就要借助正则表达式:
server {
listen 80;
server_name ~^user-(?<id>\d+)\.example\.com$;
location / {
root /var/www/users;
}
}
正则里的命名捕获组可以在后续指令中通过变量使用,比如$id可以拿到捕获到的数字。正则匹配虽然灵活,但会略微增加匹配成本,站点数量很多时需要留意。
二、反向代理场景下的域名解析:resolver与proxy_pass
当Nginx作为反向代理时,proxy_pass后面经常会写域名,例如proxy_pass http://backend.ipipp.com:8080;。很多人以为Nginx每次转发请求都会重新解析这个域名,事实并非如此。Nginx在启动或加载配置阶段就会解析proxy_pass中的域名,并把得到的IP地址缓存下来。之后只要Nginx不重新加载配置,即使backend.ipipp.com的DNS记录变了,Nginx仍然会向旧IP转发请求。
这种启动期解析的行为在大多数静态反向代理场景里影响不大,但如果后端使用动态IP、容器平台或故障切换域名,就会出现请求打到旧地址、502或连接超时等问题。解决办法是使用Nginx的resolver指令,并把proxy_pass改写成包含变量的形式:
server {
listen 80;
server_name api.ipipp.com;
resolver 223.5.5.5 valid=30s ipv6=off;
set $backend_upstream backend.ipipp.com;
location / {
proxy_pass http://$backend_upstream:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
这里resolver指定了Nginx运行时使用的DNS服务器,valid=30s表示解析结果缓存30秒。proxy_pass中使用变量后,Nginx会在每次请求时通过resolver重新解析域名,从而感知DNS变化。不过要特别注意,当proxy_pass中使用变量时,URI的传递行为和直接写域名时不同。直接写proxy_pass http://backend.ipipp.com:8080;会把原始请求URI完整拼接到后端地址,而使用变量时,如果location后面没有写具体路径,Nginx会原样转发请求URI;如果写了路径,变量的写法可能导致路径拼接不符合预期,需要谨慎测试。
另外,resolver指令也可以放在http或server层级,具体取决于作用范围。如果Nginx转发的是upstream块中定义的服务器组,那个域名解析同样是在配置加载时完成,无法通过resolver改变,需要把动态域名直接写在proxy_pass变量里。
三、完整多站点域名解析配置示例
下面给出一个比较完整的配置片段,包含默认站点拦截、静态站点和动态反向代理三种典型场景。假设域名www.ipipp.com和ipipp.com指向同一台服务器,api.ipipp.com需要代理到后端服务。
http {
resolver 223.5.5.5 valid=30s;
include /etc/nginx/mime.types;
default_type application/octet-stream;
server {
listen 80 default_server;
server_name _;
return 444;
}
server {
listen 80;
server_name www.ipipp.com ipipp.com;
location / {
root /var/www/example;
index index.html;
}
}
server {
listen 80;
server_name api.ipipp.com;
set $upstream_api backend.internal.ipipp.com;
location / {
proxy_pass http://$upstream_api:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}
第一个server块使用listen 80 default_server和server_name _,它的作用不是匹配下划线,而是作为默认虚拟主机。当请求的Host头没有命中任何server_name时,Nginx会走到这里并返回444状态码,直接关闭连接。这样可以避免未备案域名或陌生Host头访问到正式站点。
第二个server块同时监听www.ipipp.com和ipipp.com,用于静态站点。第三个server块负责API反向代理,通过变量和resolver实现后端域名的动态解析。实际生产环境中还需要根据情况配置HTTPS证书、HTTP跳转和安全头部,但域名匹配和解析的核心逻辑不变。
四、练习题与解析
几道练习题可以帮助验证对Nginx域名解析配置的理解。先看下面四个问题,再对照解析检查。
问题一:server_name *.ipipp.com能匹配a.b.ipipp.com吗?
问题二:直接写proxy_pass http://backend.ipipp.com:8080;,修改DNS记录后Nginx会立即把流量切到新IP吗?
问题三:请求Host没有匹配任何server_name时,Nginx会怎么处理?
问题四:在proxy_pass中使用变量并配置resolver后,还需要注意什么?
解析一:不能。通配符星号只能代表一段标签,所以*.ipipp.com可以匹配a.ipipp.com,但不能匹配a.b.ipipp.com。解析二:不会立即切换。Nginx会在启动或加载配置时解析并缓存该域名对应的IP,修改DNS后需要重新加载Nginx配置,或者改用resolver加变量方式让Nginx运行时动态解析。解析三:会交给默认server处理。如果没有显式配置default_server,就使用配置文件中的第一个server块。解析四:需要注意URI传递行为的变化,以及resolver的DNS服务器可用性和缓存时间设置,避免解析失败或缓存过久导致后端切换不及时。
五、常见问题与注意事项
配置Nginx域名解析时,有几个高频问题值得提前注意。首先是server_name匹配顺序。很多人配置了通配符和精确域名,结果发现精确域名没有优先生效,排查后发现是server块位置或default_server设置导致的。实际上Nginx有明确的优先级,只要理解精确、通配、正则的顺序,就能快速定位。
其次是DNS与Nginx的缓存叠加。域名A记录修改后,除了DNS服务器自身的TTL缓存,Nginx也可能缓存了proxy_pass中的IP。排查时可以先在服务器上用dig或nslookup确认DNS已经更新,再检查Nginx是否使用了变量形式做动态解析。如果两者都确认无误,还要检查系统DNS缓存和resolver配置中的valid参数。
最后是HTTPS证书与server_name的关系。在TLS握手阶段,Nginx会根据SNI扩展中的域名选择证书,这同样依赖server_name配置。如果证书覆盖的域名和server_name不一致,浏览器会报证书错误。多站点HTTPS场景下,要确保每个server块的server_name与证书SAN或CN字段匹配,必要时为不同域名配置独立证书。
另外,如果Nginx只是作为静态站点服务器,不需要在配置里写DNS解析相关指令;域名解析交给DNS服务商即可。只有反向代理后端使用域名,并且需要动态感知IP变化时,resolver才是必要的。

