原创

Nginx配置静态资源访问详解

静态资源访问是 Nginx 最常见、也最适合发挥性能优势的场景之一。图片、CSS、JavaScript、字体、下载文件这类内容通常不需要业务代码参与,直接由 Nginx 处理,链路更短、吞吐更高、资源消耗更低。

什么是静态资源访问

静态资源指的是内容不会在每次请求时动态计算的文件,例如:

  • 图片:jpgpngwebpsvg
  • 样式:css
  • 脚本:js
  • 字体:woffwoff2
  • 下载文件:zippdf
  • 前端构建产物:index.htmlassets/*

Nginx 配置静态资源访问,本质上就是把 URL 路径映射到服务器上的文件系统路径,然后由 Nginx 直接把文件返回给客户端。

为什么用 Nginx 提供静态资源

相比让 Spring Boot、Node.js、PHP 等应用服务器处理静态文件,Nginx 更适合做这件事,原因很直接:

1. 性能更高

Nginx 是事件驱动模型,处理高并发静态文件访问的成本更低。

2. 应用层压力更小

静态文件由 Nginx 直接返回,业务服务只处理动态接口,职责划分更清晰。

3. 缓存控制更方便

可以直接配置浏览器缓存、过期时间、Etag、压缩策略。

4. 安全边界更清楚

可以限定访问目录、禁止列目录、屏蔽敏感文件后缀。

静态资源访问的核心指令

配置静态资源时,最常见的是 rootaliaslocationindex

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;

含义是:

  1. 先找当前请求对应的文件
  2. 再找对应目录
  3. 都找不到时,返回 /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 到底是什么,是否和配置路径一致。

第二步:看磁盘文件路径

根据 rootalias 规则,推导出 Nginx 实际读取的文件路径。

第三步:看文件是否存在

确认目标文件确实在对应目录下。

第四步:看权限

确认 Nginx 进程用户有读权限。

第五步:看 location 是否匹配到预期规则

复杂配置里,很多问题不是文件不存在,而是请求落到了错误的 location

总结

Nginx 配置静态资源访问,重点不在于指令数量,而在于把几件事配准确:

  • URL 到磁盘路径的映射是否正确
  • rootalias 是否用对
  • 是否需要支持前端路由回退
  • 缓存策略是否区分入口页和资源文件
  • 是否限制了敏感文件访问
  • 静态文件不存在时是否返回正确状态码

真正高质量的静态资源配置通常都不复杂,但会把路径映射、缓存、安全、错误处理这几个基础点一次性处理完整。只要这几个点没有写错,Nginx 提供静态资源访问通常会非常稳定。

正文到此结束
评论插件初始化中...
Loading...