当前位置:首页>Linux>Linux、Nginx学习第四周 Nginx 的 server / location / root / alias 一篇讲透

Linux、Nginx学习第四周 Nginx 的 server / location / root / alias 一篇讲透

  • 2026-09-08 16:55:10
Linux、Nginx学习第四周 Nginx 的 server / location / root / alias 一篇讲透

上一篇把 Nginx 整体结构和第一个站点跑起来了。这一篇专门钻新人栽得最频繁、面试问得最高频的几个概念:server 怎么匹配域名、location 优先级、root 和 alias 的区别。

我自己面试候选人时,问 location 五种匹配优先级能答全的不到三成;线上 nginx 配置改错的事故,一半以上是 root / alias 用混了。这一篇按真实排查流程讲透。


一、server 是怎么被匹配上的

一台 Nginx 上常常跑十几个 server(虚拟主机),来一个请求选哪个 server 处理?走这个顺序:

1. 先按 listen 端口过滤(只看监听同一端口的 server)2. 再按 server_name 匹配(精确 → 通配符 → 正则 → default_server)

第一步:listen 端口

nginx
server {listen80;server_name a.example.com;}server {listen8080;server_name a.example.com;}

同一个 a.example.com,访问 80 端口走第一个,访问 8080 走第二个。端口是硬过滤。

第二步:server_name 四级优先级

优先级
写法
例子
命中
1(最高)
精确匹配
server_name a.example.com;a.example.com
2
前缀通配符
server_name *.example.com;x.example.com
 / y.example.com
3
后缀通配符
server_name example.*;example.com
 / example.cn
4
正则匹配
server_name ~^api\d+\.example\.com$;api1.example.com
5(兜底)
default_server
listen 80 default_server;
都不匹配时走它

注意一个反直觉的点:正则优先级比通配符低。*.example.com 会先吃掉,正则只在通配符没命中时才匹配。

server_name 实用写法

nginx
# 精确单个server_name a.example.com;# 多个精确(一个 server 服务多域名)server_name a.example.com b.example.com;# 通配符server_name*.example.com;# 主域 + 所有子域server_name example.com *.example.com;# 兜底:catch-allserver_name _;# 正则(必须 ~ 开头)server_name ~^api(?<num>\d+)\.example\.com$;

listen 写法的几个变种

nginx
listen80;                          # IPv4 任意地址listen [::]:80;                     # IPv6 任意地址listen80 default_server;           # 标记为默认 server(**同一端口只能有一个 default**)listen443 ssl http2;               # HTTPS + HTTP/2(注意 1.25.1 起推荐写 `http2 on;`)listen unix:/run/nginx-internal.sock;   # Unix socket(内部转发用)listen80 reuseport;                # 启用 SO_REUSEPORT,多 worker 各自 accept(高并发场景)

default_server 的重要性:

如果一个请求带的 Host 头谁都不匹配(比如别人拿你的 IP 直接打),会走 default_server。没显式指定时,会走「同端口下第一个 server」,常常导致莫名其妙的请求被某个不相关的 server 接走。生产配置永远建议:

nginx
# 第一个 server 就放个明确的 default,拒绝未识别 Hostserver {listen80 default_server;server_name _;return444;       # nginx 内部状态码,直接关闭连接不返回}

二、location 五种匹配方式与优先级(面试高频)

server 选好之后,按 URL 路径匹配 location。location 有五种写法,优先级不是从上到下,而是按修饰符决定。

优先级
修饰符
含义
例子
1(最高)
=精确匹配
,命中就停
location = /favicon.ico
2
^~
前缀匹配,命中就停(不再走正则)
location ^~ /static/
3
~区分大小写正则
,按配置顺序
location ~ \.php$
3
~*不区分大小写正则
,按配置顺序
location ~* \.(jpg|png)$
4(最低)
(无)
普通前缀,记录最长匹配后继续
location /api/

匹配流程总结一句话

Nginx 先把所有前缀 location(无修饰符 + ^~ + =)扫一遍,挑出最长前缀;如果最长前缀是 = 或 ^~,直接定;否则继续按配置顺序匹配正则 location,命中正则就走正则,没命中走那个最长前缀。

用一个完整例子演示

nginx
server {listen80;server_name demo.local;location = / {return200"A: 精确根路径\n";    }location = /favicon.ico {return200"B: 精确 favicon\n";    }location ^~ /static/ {return200"C: ^~ /static/\n";    }location~ \.php$ {return200"D: 正则 .php\n";    }location~* \.(jpg|png|gif)$ {return200"E: 正则不区分大小写图片\n";    }location /api/ {return200"F: 普通前缀 /api/\n";    }location / {return200"G: 普通前缀 / (兜底)\n";    }}

访问不同 URL 命中谁:

请求 URL
命中
原因
/
A
=
 精确匹配
/favicon.ico
B
=
 精确匹配
/static/css/app.css
C
^~
 命中后停(不再走正则)
/static/image.PNG
C
同上,虽然像图片但 ^~ 阻断了正则
/index.php
D
没前缀强约束,走正则 \.php$
/photo.jpg
E
同上,走 ~* 正则
/photo.JPG
E
大小写不敏感
/api/users
F
最长前缀 /api/,没匹配到正则就走它
/about
G
啥都不匹配,走兜底 /

面试题最爱问的两点:

  • ^~ 不是「正则」,是「前缀但抑制正则」
    。新人爱说成「^~ 是开头匹配」,是错的——它是前缀匹配里的一个修饰,命中后直接跳过正则阶段
  • 正则之间按出现顺序匹配
    ,普通前缀按最长匹配。所以正则的相对顺序很重要,普通前缀的写法顺序不重要

三、root vs alias 的关键差异(踩坑王)

这两个指令都用来「告诉 nginx 文件在磁盘的哪儿」,但逻辑完全不同:

  • root
    :拼接 location 的路径
  • alias
    :替换 location 的路径

用同一个请求演示

请求 URL:/static/x.png

nginx
# 写法 1:用 rootlocation /static/ {root /var/www;}# Nginx 拼接:root + 完整 URI# 实际磁盘路径:/var/www/static/x.png# 写法 2:用 aliaslocation /static/ {alias /var/www/assets/;}# Nginx 替换:alias 替换掉 location 部分# 实际磁盘路径:/var/www/assets/x.png# 写法 3:alias 路径与 location 不同名(最常见用法)location /imgs/ {alias /data/pictures/;}# 请求 /imgs/cat.jpg → 磁盘 /data/pictures/cat.jpg

一张对照表

维度
root
alias
路径关系
拼接(保留 location 部分)
替换(去掉 location 部分)
末尾斜杠
不严格要求
alias 是目录时必须以 / 结尾
可用位置
http / server / location
只能用在 location 内
与正则配合
直接用
正则 location 用 alias 要写 $1 类捕获
推荐写在哪
server 级写一份默认
各 location 各自指定

root 的最佳实践

默认把 root 写在 server 级别一份,各 location 不重复写:

nginx
server {listen80;server_name demo.local;root /var/www/my-site;        # ← 默认根目录location / {try_files$uri$uri/ /index.html;    }location /docs/ {# 没写 root,自动用 server 级别的 /var/www/my-site# 请求 /docs/a.html → /var/www/my-site/docs/a.html    }location /assets/ {# 想给 /assets 单独换路径,这里覆盖alias /opt/cdn-cache/;# 请求 /assets/main.css → /opt/cdn-cache/main.css    }}

alias 三个最高频踩坑

nginx
# ❌ 坑 1:alias 末尾没斜杠location /static/ {alias /var/www/assets;    # 缺 /}# 请求 /static/x.png 实际去找 /var/www/assetsx.png(路径被拼坏)# ✅ 正确:location 和 alias 都要么都有 /,要么都没 /location /static/ {alias /var/www/assets/;}# ❌ 坑 2:在 server 上下文用了 aliasserver {alias /var/www/x;         # ❌ alias 不能用在 server 级}# ❌ 坑 3:正则 location 配 alias 用错变量location~ ^/imgs/(.+)\.jpg$ {alias /data/$1.jpg;        # 这种写法在新版 nginx 已不推荐,建议 try_files}

四、try_files 的妙用:SPA 兜底必备

try_files 让 nginx 按顺序尝试多个文件,第一个存在的就用,全都不存在走最后一个(可以是一个 URI 或状态码)。

静态文件兜底 404

nginx
location / {try_files$uri$uri/ =404;# 1. 试 $uri 本身是不是文件# 2. 试 $uri/ 是不是目录(自动找 index)# 3. 都没有,返回 404}

SPA 单页应用(Vue / React)

nginx
location / {try_files$uri$uri/ /index.html;# 文件在就给文件,否则统统返回 index.html# 这样前端路由刷新 /users/123 也不会 404}

没有这一行,前端路由刷新就死——Nginx 看到 /users/123 不存在直接 404,因为这个 URL 是前端 router 在浏览器里识别的,nginx 不知道。

PHP 应用经典写法

nginx
location / {try_files$uri$uri/ /index.php?$query_string;}location~ \.php$ {fastcgi_pass unix:/run/php/php8.2-fpm.sock;fastcgi_index index.php;include fastcgi_params;fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;}

五、「我的图片为什么 404」标准排查流程

新人最常问的问题之一:「配了 nginx 但图片访问 404,配置看着没问题」。按这个流程排:

Step 1:看 error.log 里的实际路径

bash
sudotail -f /var/log/nginx/error.log# 再访问一次出问题的 URL,等错误打出来

会看到类似:

*123 open() "/var/www/static/static/img/x.png" failed (2: No such file or directory),client: 127.0.0.1, server: demo.local, request: "GET /static/img/x.png HTTP/1.1"

注意 /var/www/static/static/img/x.png——多了一个 static。说明 root 拼接出了重复路径,应该改用 alias 或调整 root。

Step 2:核对 root / alias 配置

nginx
# 假设原配置location /static/ {root /var/www/static;     # ← root 会拼上 location,变成 /var/www/static/static/...}# 修正方案 A:去掉 root 里的 staticlocation /static/ {root /var/www;            # → /var/www/static/img/x.png}# 修正方案 B:用 aliaslocation /static/ {alias /var/www/static/;   # → /var/www/static/img/x.png}

Step 3:文件权限和属主

bash
sudo -u www-data ls /var/www/static/img/x.png# 如果 Permission denied 就是权限问题# Nginx 用户需要:目录有 x(能进入)+ 文件有 r(能读)sudochown -R www-data:www-data /var/www/staticsudochmod -R 755 /var/www/static

Step 4:用 nginx debug 看真实匹配过程(杀手锏)

nginx
# error_log 改成 debug 级别(**仅排查时开**)error_log /var/log/nginx/error.log debug;

reload 后再请求一次,error.log 里会有:

test location: "/static/"using configuration "/static/"http filename: "/var/www/static/img/x.png"

直接告诉你它命中了哪个 location、拼出了什么路径,排错一目了然。


六、internal 与 X-Accel-Redirect:高级用法

location 加 internal 表示只能被内部 rewrite / redirect 进入,不能从外部 URL 直接访问。

nginx
location /protected/ {    internal;                                  # 外部 GET /protected/x 直接 404alias /var/www/protected-files/;}location /api/download/ {# 应用做鉴权后,回 X-Accel-Redirect 头给 nginxproxy_pass http://backend;}

后端 PHP / Node 校验通过后回 header X-Accel-Redirect: /protected/big-file.pdf,nginx 接到这个头会内部转发到 /protected/ 由它来发文件,应用本身不传文件、不耗带宽——这是大文件下载鉴权的经典模式。


七、配置最佳实践小抄

nginx
server {# ━━ listen ━━listen80;listen [::]:80;                              # 同时听 IPv6# ━━ server_name ━━server_name www.example.com example.com;# ━━ 根路径写在 server 级,全 server 共享 ━━root /var/www/example;index index.html;# ━━ 日志分站点 ━━access_log /var/log/nginx/example.access.log;error_log  /var/log/nginx/example.error.log warn;# ━━ 通用 location ━━location / {try_files$uri$uri/ =404;    }# ━━ 静态资源单独缓存 ━━location~* \.(jpg|png|css|js)$ {expires7d;add_header Cache-Control "public, immutable";    }# ━━ 隐藏文件拒绝访问 ━━location~ /\. {deny all;access_logoff;log_not_foundoff;    }# ━━ 转发 API 到后端 ━━location /api/ {proxy_pass http://127.0.0.1:3000/;       # 注意结尾的 /,下一篇详讲proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;    }}

八、常见错误总结

错误现象
真实原因
怎么改
配置 reload 后没生效
sites-available 改了但没软链到 sites-enabled
ln -s sites-available/x sites-enabled/
图片 404 但配置看着没错
root 拼出重复路径
改用 alias 或调整 root
前端 SPA 路由刷新 404
没配 try_files 兜底
try_files $uri $uri/ /index.html;
多个 location 都该匹配,结果走了不对的
没理解 ^~ 阻断正则、正则按顺序
重新梳理 location 优先级
别人拿 IP 直接打到你的站
没设 default_server 拒绝
加一个 return 444; 的 default
alias 路径拼坏
末尾斜杠不一致
location 和 alias 末尾要么都带 / 要么都不带

写在最后

  • server 选谁,先按 listen 端口,再按 server_name(精确 > 通配 > 正则 > default)
  • location 五优先级背熟
    := > ^~ > ~/~*(按顺序) > 普通前缀(按最长)
  • ^~ 不是「正则」,是「前缀且阻断正则」
  • root 拼接、alias 替换
    ——这一句记牢,95% 的路径问题都能避开
  • alias 必须末尾带 /(如果指向目录)
    ,且只能用在 location 内
  • SPA 项目 location / 里 try_files $uri $uri/ /index.html;是必备
  • 排查路径问题先开 error_log debug,nginx 会告诉你它命中了哪个 location、拼出了什么真实磁盘路径

最新文章

随机文章