Chapter 03

server 与 location

请求进来,Nginx 先选一个 server(虚拟主机),再在其中选一个 location(URL 规则)。这两步匹配是所有配置的核心,location 优先级更是经典考点。

3.1 核心概念

虚拟主机(Virtual Host / server 块)
一台 Nginx 可用多个 server{} 块托管多个域名/站点。靠 listenserver_name 区分请求该由哪个 server 处理。
server_name
匹配请求 Host 头的域名。支持精确名、通配符(*.example.com)、正则(~^www\.)。决定虚拟主机归属。
listen
指定监听的 IP:端口,以及 default_serversslhttp2 等标志。同一端口可有多个 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(没显式指定则用第一个)。

server_name 匹配优先级

精确名 > 前缀通配 *.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 的实际算法是:

  1. 先检查所有精确匹配 = 。命中则立即使用,结束。
  2. 再检查所有前缀匹配(普通前缀 + ^~),记住"最长匹配"的那个。
  3. 若最长前缀带 ^~,直接用它,不再检查正则
  4. 否则按配置文件顺序检查正则,第一个命中的正则胜出。
  5. 没有正则命中,则回退用第 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 结尾斜杠必须对齐

用 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 小结与下一步