Nginx 通过独立 server 块+server_name 指令按 Host 头匹配路由:主站与子域名需分设不同 server 块,各声明对应域名;匹配优先级为正则>精确>通配符前缀>后缀>兜底;HTTPS 下须共用含全部域名的 SAN 证书。

Nginx 用 server_name 区分主站和子域名,本质是靠 HTTP 请求里的 Host 头匹配不同 server 块,而不是在同一个块里做判断。关键不是“怎么写条件”,而是“怎么组织 server 块”——结构对了,路由自然就分开了。
明确主站和子域名各自走独立 server 块
主站(如 example.com)和子域名(如 blog.example.com、api.example.com)应配置为不同的 server{} 块,每个块监听相同端口(80/443),但 server_name 各自声明对应域名。Nginx 收到请求后,提取 Host 头,按优先级逐个比对所有 server_name,命中即交由该块处理。
-
主站块示例:
server { listen 80; server_name example.com www.example.com; root /var/www/main; index index.html; } -
子域名块示例:
server { listen 80; server_name blog.example.com; root /var/www/blog; index index.html; } server { listen 80; server_name api.example.com; location / { proxy_pass http://127.0.0.1:3001; } }
匹配顺序决定谁先抢到请求
Nginx 不是“全量匹配”,而是按固定优先级找第一个能匹配的 server_name,后续块不再检查。优先级从高到低为:
- 正则匹配(以
~或~*开头) - 精确匹配(如
example.com) - 通配符前缀(如
*.example.com) - 通配符后缀(如
mail.*) -
_或未设server_name的兜底块
⚠️ 注意:*.example.com 不匹配 example.com(缺子域),所以主站必须单独写精确匹配。
HTTPS 下子域名必须共用 SAN 证书
如果主站和子域名都走 HTTPS,不能给每个 server 块配不同证书。必须用一张含全部域名的 SAN 证书,例如:
certbot -d example.com -d www.example.com -d blog.example.com -d api.example.com
然后所有 server 块共用同一组 ssl_certificate 和 ssl_certificate_key 指令。SNI 协商阶段只校验首个 server_name 是否在证书 SAN 列表中,其余域名靠 HTTP 层的 Host 匹配生效。
测试时别被 curl 默认行为骗了
直接 curl http://127.0.0.1 不带 Host 头,Nginx 会交给第一个加载的 server 块(或 default_server)。要模拟真实访问,必须显式指定:
curl -H "Host: blog.example.com" http://127.0.0.1
本地测试记得同步改 /etc/hosts:
127.0.0.1 example.com blog.example.com api.example.com
不复杂但容易忽略。



















