3.1 核心概念
- 虚拟主机(Virtual Host / server 块)
- 一台 Nginx 可用多个
server{}块托管多个域名/站点。靠listen和server_name区分请求该由哪个 server 处理。 - server_name
- 匹配请求 Host 头的域名。支持精确名、通配符(
*.example.com)、正则(~^www\.)。决定虚拟主机归属。 - listen
- 指定监听的 IP:端口,以及
default_server、ssl、http2等标志。同一端口可有多个 server,靠 server_name 二次区分。 - location
- 在选定的 server 内,根据请求 URI 选择处理规则的块。匹配方式有前缀、精确、正则等,优先级复杂。
- root
- 指定文档根目录。最终文件路径 =
root 值 + 完整 URI。 - alias
- 为 location 指定一个替换路径。最终路径 =
alias 值 + (URI 去掉 location 前缀的部分)。与 root 的拼接规则不同,极易踩坑。
3.2 虚拟主机:一台机器托管多个域名
# 站点 A
server {
listen 80;
server_name a.example.com;
root /var/www/site-a;
}
# 站点 B
server {
listen 80;
server_name b.example.com;
root /var/www/site-b;
}
# 兜底:匹配不到任何 server_name 时用它
server {
listen 80 default_server;
server_name _;
return 444; # 直接断开,不给响应
}
Nginx 选 server 的流程:先按 listen 过滤出监听该 IP:端口的所有 server,再用请求的 Host 头去匹配 server_name。都不匹配时,用该端口的 default_server(没显式指定则用第一个)。
精确名 > 前缀通配 *.example.com > 后缀通配 www.example.* > 正则(按出现顺序)。定义了 default_server 的作为最后兜底。写一个返回 444 的默认 server,能有效挡掉扫描器用 IP 直连的垃圾请求。
3.3 listen 的常见写法
listen 80; # 所有 IP 的 80 端口
listen 443 ssl; # HTTPS
listen 443 ssl default_server; # 兼作默认 server
listen 127.0.0.1:8080; # 只监听本机
listen [::]:80; # IPv6
listen 80 reuseport; # 内核负载均衡,减少惊群
3.4 location 的五种匹配方式
| 写法 | 含义 | 优先级 |
|---|---|---|
location = /path | 精确匹配,URI 完全等于才命中 | 最高 |
location ^~ /path | 前缀匹配,命中后不再看正则 | 次高 |
location ~ regex | 正则匹配(区分大小写) | 中 |
location ~* regex | 正则匹配(不区分大小写) | 中 |
location /path | 普通前缀匹配 | 最低(做兜底) |
3.5 location 优先级完整规则
这是 Nginx 最容易搞混的部分。Nginx 选 location 的实际算法是:
- 先检查所有精确匹配
=。命中则立即使用,结束。 - 再检查所有前缀匹配(普通前缀 +
^~),记住"最长匹配"的那个。 - 若最长前缀带
^~,直接用它,不再检查正则。 - 否则按配置文件顺序检查正则,第一个命中的正则胜出。
- 没有正则命中,则回退用第 2 步记住的最长前缀。
server {
listen 80;
server_name example.com;
root /var/www;
location = / {
# 只匹配 http://example.com/ (精确)
try_files /index.html =404;
}
location ^~ /static/ {
# /static/ 开头一律走这里,不再看下面的正则
expires 30d;
}
location ~* \.(jpg|png|gif|css|js)$ {
# 图片和静态资源(正则,不区分大小写)
expires 7d;
}
location / {
# 兜底:其它所有请求
try_files $uri $uri/ /index.html;
}
}
^~ 常用于静态目录
如果只写 location /static/(普通前缀),当请求 /static/app.js 时,Nginx 会先记住这个前缀,然后仍去尝试上面的 ~* \.js$ 正则——结果被正则规则接管。加上 ^~ 就能明确告诉 Nginx:"命中这个前缀就别看正则了",避免规则打架。
3.6 root 与 alias 的致命区别
两者都指定磁盘路径,但拼接方式完全不同:
root:拼接完整 URI
请求 /img/a.png
root /data;
→ 文件路径 /data/img/a.png
alias:替换 location 前缀
请求 /img/a.png
location /img/ { alias /data/pics/; }
→ 文件路径 /data/pics/a.png
# root:URI 会被完整追加到 root 后面
location /download/ {
root /var/files; # /download/x → /var/files/download/x
}
# alias:location 前缀被 alias 值替换
location /download/ {
alias /var/files/; # /download/x → /var/files/x
}
用 alias 时,location 前缀和 alias 值的结尾斜杠要么都有、要么都没有,否则路径会错乱。经验法则:能用 root 就用 root,只有当磁盘目录名和 URL 路径不一致时才用 alias,且务必两端都带 /。
3.7 一个完整示例
server {
listen 80;
server_name shop.example.com;
# 前端静态资源目录名与 URL 不同 → alias
location /assets/ {
alias /var/www/shop/dist/assets/;
expires 30d;
}
# 健康检查精确路径
location = /healthz {
return 200 "ok\n";
add_header Content-Type text/plain;
}
# 其余走前端入口(SPA)
location / {
root /var/www/shop/dist;
try_files $uri /index.html;
}
}
3.8 小结与下一步
- 请求匹配分两步:先按 listen+server_name 选 server,再按 URI 选 location。
- location 优先级:精确
=>^~前缀 > 正则(按序)> 普通前缀兜底。 ^~命中后不再看正则,最适合静态目录,避免规则打架。- root 拼接完整 URI,alias 替换 location 前缀——alias 的斜杠对齐是高频 bug。
- 下一章讲 静态资源服务——index、autoindex、gzip、缓存头、try_files 与错误页。