Nginx配置静态资源访问详解
静态资源访问是 Nginx 最常见、也最适合发挥性能优势的场景之一。图片、CSS、JavaScript、字体、下载文件这类内容通常不需要业务代码参与,直接由 Nginx 处理,链路更短、吞吐更高、资源消耗更低。
什么是静态资源访问
静态资源指的是内容不会在每次请求时动态计算的文件,例如:
- 图片:
jpg、png、webp、svg - 样式:
css - 脚本:
js - 字体:
woff、woff2 - 下载文件:
zip、pdf - 前端构建产物:
index.html、assets/*
Nginx 配置静态资源访问,本质上就是把 URL 路径映射到服务器上的文件系统路径,然后由 Nginx 直接把文件返回给客户端。
为什么用 Nginx 提供静态资源
相比让 Spring Boot、Node.js、PHP 等应用服务器处理静态文件,Nginx 更适合做这件事,原因很直接:
1. 性能更高
Nginx 是事件驱动模型,处理高并发静态文件访问的成本更低。
2. 应用层压力更小
静态文件由 Nginx 直接返回,业务服务只处理动态接口,职责划分更清晰。
3. 缓存控制更方便
可以直接配置浏览器缓存、过期时间、Etag、压缩策略。
4. 安全边界更清楚
可以限定访问目录、禁止列目录、屏蔽敏感文件后缀。
静态资源访问的核心指令
配置静态资源时,最常见的是 root、alias、location、index。
root 的作用
root 表示设置资源根目录。Nginx 在匹配到请求后,会把 location 匹配到的 URI 直接拼接到 root 指定的目录后面。
示例:
server {
listen 80;
server_name localhost;
location /images/ {
root /usr/share/nginx/html;
}
}
请求:
http://localhost/images/logo.png
Nginx 实际查找的文件路径是:
/usr/share/nginx/html/images/logo.png
可以看到,/images/logo.png 中的 /images/ 会保留下来,和 root 进行拼接。
alias 的作用
alias 也是做路径映射,但它不是拼接完整 URI,而是用指定目录替换掉当前 location 匹配部分。
示例:
server {
listen 80;
server_name localhost;
location /images/ {
alias /data/static/images/;
}
}
请求:
http://localhost/images/logo.png
Nginx 实际查找的文件路径是:
/data/static/images/logo.png
这里 /images/ 被 alias 替换掉了。
root 和 alias 的区别
这是 Nginx 静态资源配置里最容易写错的地方。
| 指令 | 路径拼接方式 | 适用场景 |
|---|---|---|
| root | root目录 + 完整请求URI | 目录结构与URL结构基本一致 |
| alias | alias目录 + 去掉location前缀后的剩余部分 | URL结构与实际目录结构不一致 |
对比例子
配置一:
location /static/ {
root /var/www;
}
请求:
/static/app.js
实际文件路径:
/var/www/static/app.js
配置二:
location /static/ {
alias /var/www/assets/;
}
请求:
/static/app.js
实际文件路径:
/var/www/assets/app.js
结论
- URL 路径和磁盘目录结构一致,优先考虑
root - URL 前缀只是访问标识,而真实目录是另一个路径,使用
alias
最基础的静态资源访问配置
下面是一份最常见的静态资源配置:
server {
listen 80;
server_name example.com;
location / {
root /usr/share/nginx/html;
index index.html;
}
}
如果目录结构如下:
/usr/share/nginx/html/
├── index.html
├── css/
│ └── app.css
├── js/
│ └── app.js
└── images/
└── logo.png
那么访问结果如下:
/->/usr/share/nginx/html/index.html/css/app.css->/usr/share/nginx/html/css/app.css/js/app.js->/usr/share/nginx/html/js/app.js/images/logo.png->/usr/share/nginx/html/images/logo.png
这类配置非常适合部署纯静态站点,或者部署前后端分离项目的前端构建结果。
按目录单独配置静态资源
很多项目不会把所有静态资源都放在一个统一目录下,而是按资源类型单独管理。
示例:
server {
listen 80;
server_name example.com;
location /img/ {
alias /data/www/images/;
}
location /css/ {
alias /data/www/css/;
}
location /js/ {
alias /data/www/js/;
}
}
这样有几个直接好处:
- 目录职责清晰
- 更容易单独配置缓存策略
- 出问题时定位更快
部署前端项目时的典型配置
以前端构建产物为例,假设 dist 目录如下:
dist/
├── index.html
├── favicon.ico
└── assets/
├── index-abc123.js
└── index-def456.css
可以这样配置:
server {
listen 80;
server_name example.com;
root /data/www/dist;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
}
为什么要用 try_files
单页应用前端路由使用的是浏览器路径,例如:
/user/profile
/order/list
这些路径在服务器上通常并没有真实文件。如果不加 try_files,Nginx 会直接返回 404。
try_files $uri $uri/ /index.html;
含义是:
- 先找当前请求对应的文件
- 再找对应目录
- 都找不到时,返回
/index.html
这样前端路由就能交给 Vue Router、React Router 之类的路由系统处理。
配置图片、CSS、JS 的独立访问规则
实际项目中,一般会给静态资源单独写规则,便于开启缓存和日志优化。
server {
listen 80;
server_name example.com;
root /data/www/dist;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location ~* \.(jpg|jpeg|png|gif|webp|svg|css|js|woff|woff2)$ {
root /data/www/dist;
expires 30d;
access_log off;
}
}
这里有几个关键点:
location ~*
表示不区分大小写的正则匹配。
expires 30d
告诉浏览器该资源可以缓存 30 天。适合带 hash 的静态文件,例如:
index-abc123.js
style-98fa21.css
access_log off
关闭这类资源的访问日志,减少无意义日志量。
使用 expires 控制缓存
浏览器缓存是静态资源优化的重点。Nginx 可以通过 expires 快速设置缓存时间。
常见写法:
expires 1h;
expires 7d;
expires 30d;
expires max;
expires -1;
含义分别是:
1h:缓存 1 小时7d:缓存 7 天30d:缓存 30 天max:尽可能长时间缓存-1:通常表示不缓存或立即过期
推荐策略:
| 资源类型 | 建议缓存时间 |
|---|---|
| 带 hash 的 js/css | 30d 或更长 |
| 图片、字体 | 7d 到 30d |
| index.html | 不建议长缓存 |
| 接口响应 | 不属于静态资源,不应套用该策略 |
这里最重要的一点是:index.html 不要配置长缓存,否则前端发布新版本后,用户可能一直拿到旧入口文件。
index.html 与静态资源分开缓存
更稳妥的做法是把入口页和资源文件分开处理。
server {
listen 80;
server_name example.com;
root /data/www/dist;
index index.html;
location = /index.html {
expires -1;
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
location / {
try_files $uri $uri/ /index.html;
}
location ~* \.(js|css|png|jpg|jpeg|gif|svg|woff|woff2)$ {
expires 30d;
add_header Cache-Control "public";
access_log off;
}
}
autoindex:是否允许目录浏览
如果访问的是目录,目录下又没有 index.html,可以决定是否让 Nginx 显示目录列表。
示例:
location /download/ {
alias /data/download/;
autoindex on;
}
访问 /download/ 时,会显示 /data/download/ 目录下的文件列表。
什么时候可以开
- 内部文件分发
- 测试环境下载目录
- 简单文件共享场景
什么时候不要开
- 面向公网的正式环境
- 包含敏感文件命名信息的目录
- 不希望暴露目录结构的场景
生产环境通常建议关闭:
autoindex off;
下载文件目录配置示例
server {
listen 80;
server_name download.example.com;
location /files/ {
alias /data/downloads/;
autoindex off;
}
}
请求:
http://download.example.com/files/manual.pdf
映射到:
/data/downloads/manual.pdf
防止访问敏感文件
静态资源目录中常见风险不是资源本身,而是误把敏感文件放进去了,例如:
.git.env.htaccess- 备份文件:
.bak - 临时文件:
.swp
可以直接拒绝访问:
location ~ /\.(git|env) {
deny all;
}
location ~* \.(bak|swp|tmp)$ {
deny all;
}
这样即使文件误上传到了静态目录,也不会被直接访问。
配置 404 页面
静态资源访问中,404 处理也应该明确配置,否则排查问题时不够直观。
server {
listen 80;
server_name example.com;
root /data/www/dist;
index index.html;
error_page 404 /404.html;
location = /404.html {
internal;
}
location / {
try_files $uri $uri/ =404;
}
}
这里 internal 表示外部不能直接访问 /404.html,只有 Nginx 内部错误转发时才能使用。
常见错误一:root 和 alias 混用不当
错误配置:
location /static/ {
alias /data/www/static;
}
这个配置少了结尾斜杠,虽然在某些场景下可能还能工作,但很容易引起路径拼接歧义。更稳妥的写法是:
location /static/ {
alias /data/www/static/;
}
经验上可以直接记住一条规则:
location /xxx/配合alias /path/,两边都带斜杠- 这样最不容易出错
常见错误二:静态目录权限不足
即使 Nginx 配置没问题,文件也可能访问失败,原因是 Nginx 工作进程用户没有读取权限。
例如:
/data/www/dist/index.html
如果该文件所属权限不允许 Nginx 用户读取,就会返回 403 Forbidden。
排查重点:
- 文件是否存在
- 目录是否可进入
- 文件是否可读
- Nginx 运行用户是谁
在 Linux 中通常需要保证:
- 目录具备执行权限
- 文件具备读取权限
常见错误三:try_files 导致静态文件误回退到 index.html
错误配置示例:
location / {
try_files $uri /index.html;
}
如果资源路径拼错,例如访问 /assets/app.js,但实际文件不存在,Nginx 可能回退到 index.html,浏览器收到 HTML 内容后会报 JS 加载错误。
更合理的做法是区分入口页回退和静态文件访问:
location / {
try_files $uri $uri/ /index.html;
}
location ~* \.(js|css|png|jpg|jpeg|gif|svg|woff|woff2)$ {
try_files $uri =404;
expires 30d;
access_log off;
}
这样静态资源不存在时直接返回 404,不会错误返回 HTML。
常见错误四:给所有文件都设置长缓存
错误示例:
location / {
expires 30d;
}
这样会把 index.html 也缓存很久。前端一旦发布新版本,用户端就可能迟迟不更新。
正确方式是:
- 入口页不缓存或短缓存
- 带 hash 的资源长缓存
常见错误五:location 匹配顺序理解错误
Nginx 的 location 匹配有优先级,静态资源配置常常会被更上层规则覆盖。
例如:
location / {
try_files $uri $uri/ /index.html;
}
location ~* \.(js|css)$ {
expires 30d;
}
这类配置通常是可行的,但如果还有更复杂的 location 规则,比如 ^~、更具体的路径前缀、正则冲突,就可能导致结果和预期不一致。
静态资源配置时应遵循一个原则:访问规则尽量简单,资源路径尽量稳定,不要堆过多互相覆盖的匹配逻辑。
一份推荐的生产配置示例
下面是一份更接近生产环境的前端静态资源配置:
server {
listen 80;
server_name example.com;
root /data/www/dist;
index index.html;
location = /index.html {
expires -1;
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
location / {
try_files $uri $uri/ /index.html;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|webp|woff|woff2)$ {
try_files $uri =404;
expires 30d;
add_header Cache-Control "public";
access_log off;
}
location ~ /\.(git|env|svn) {
deny all;
}
location ~* \.(bak|tmp|swp)$ {
deny all;
}
}
这份配置解决了几个关键问题:
- 前端路由可正常刷新
- 静态资源走长缓存
- 静态资源缺失直接返回 404
- 入口页不长缓存
- 敏感文件禁止访问
一份纯文件目录映射配置示例
如果不是前端单页应用,而只是单纯暴露静态文件目录,可以更直接:
server {
listen 80;
server_name static.example.com;
location /static/ {
alias /data/static/;
expires 7d;
access_log off;
}
location /download/ {
alias /data/download/;
autoindex off;
}
location ~ /\.(git|env) {
deny all;
}
}
这个场景适合:
- 图片服务器
- 文件下载服务器
- 后台上传资源访问
- 独立静态资源域名
如何验证配置是否生效
修改完配置后,至少要做三步检查。
1. 检查配置语法
nginx -t
如果输出语法检查通过,再执行重载。
2. 重载配置
nginx -s reload
或者使用 systemd:
systemctl reload nginx
3. 实际访问验证
重点验证以下几类 URL:
- 存在的静态文件是否能访问
- 不存在的静态文件是否返回 404
- 前端路由刷新是否正常
- 敏感文件是否被拒绝
index.html和资源文件的缓存头是否符合预期
排查静态资源访问问题的顺序
出问题时,不要一上来改配置,先按顺序排查。
第一步:看请求路径
确认浏览器请求的 URL 到底是什么,是否和配置路径一致。
第二步:看磁盘文件路径
根据 root 或 alias 规则,推导出 Nginx 实际读取的文件路径。
第三步:看文件是否存在
确认目标文件确实在对应目录下。
第四步:看权限
确认 Nginx 进程用户有读权限。
第五步:看 location 是否匹配到预期规则
复杂配置里,很多问题不是文件不存在,而是请求落到了错误的 location。
总结
Nginx 配置静态资源访问,重点不在于指令数量,而在于把几件事配准确:
- URL 到磁盘路径的映射是否正确
root和alias是否用对- 是否需要支持前端路由回退
- 缓存策略是否区分入口页和资源文件
- 是否限制了敏感文件访问
- 静态文件不存在时是否返回正确状态码
真正高质量的静态资源配置通常都不复杂,但会把路径映射、缓存、安全、错误处理这几个基础点一次性处理完整。只要这几个点没有写错,Nginx 提供静态资源访问通常会非常稳定。