DEBUG.WIKI
京东云;让 AI 进入真实业务;零售 · 物流 · 客服 · 硬件;查看方案 →
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
Evoxt;最高 6.0GHz CPU;高频云服务器 · 免费每周备份;查看配置 →

Nginx 把 alias 改成正则 location 后,文件返回 404

alias 在正则 location 中需要明确完整文件路径;检查捕获结果、实际磁盘路径和其他 location 的匹配次序。

原来用前缀 location /assets/ 能访问的文件,改成正则 location 后返回 404。如果 alias 仍只指向目录,先核对它是否构成了完整的目标文件路径。正则 location 下的 alias,不能直接沿用前缀匹配时自动替换路径前缀的理解。

本文处理静态文件的 URI 到磁盘路径映射。Laravel 等应用同时还有重写、入口 PHP 和 FastCGI 参数;静态映射修好后,不代表应用路由一定已经恢复。

把请求路径和磁盘路径放在一起看

前缀形式的示例可以这样写:

location /assets/ {
    alias /srv/static/;
}

访问 /assets/logo.png,目标文件是 /srv/static/logo.png。如果只是把 location 改成下面的正则,却保留目录 alias,就没有为这个正则映射明确提供文件路径:

location ~ ^/assets/(.*)$ {
    alias /srv/static/;
}

正则 location 中,alias 的值指定完整文件路径,通常应引用正则捕获结果。Nginx 不会像上述前缀形式那样,自行把未匹配的文件名尾部追加到 alias 目录。

检查错误日志实际尝试的路径,或在受控诊断日志中检查 $request_filename。如果目标只是目录,或多出了 URI 前缀,修改映射;如果路径已经正确,则转向文件是否存在、目录搜索权限和文件读取权限。不要把所有 404 都归因于正则。

固定前缀不需要正则;需要正则时限制捕获范围

如果只想把 /assets/ 映射到固定目录,保留前缀 location 就够了。确实需要按产品目录分流时,可以给产品名和静态文件名分别设置捕获。例如,以下示例只提供选定后缀、不包含子目录的文件:

location ~ ^/assets/(?<product>[a-z][a-z0-9_-]*)/(?<asset>[^/]+\.(?:css|js|png))$ {
    alias /srv/products/$product/public/$asset;
}

请求 /assets/demo/app.css 对应 /srv/products/demo/public/app.css。目录和名称规则都是示例,必须符合实际的公开资源布局。这个规则只允许一种有限格式,不是通用文件浏览器;不要直接用贪婪的 (.*) 捕获产品名,把整段剩余路径当成目录名称。

如果不需要多产品目录,固定目录与文件名捕获会更容易核对。不要为了修复一个静态文件,开放应用配置、密钥或其他原本不公开的目录。

正则之间的匹配次序也会影响结果

Nginx 按配置次序检查正则 location,使用第一个匹配项。更早的图片、PHP 或其他扩展名正则,可能让请求进入另一套 root 或 FastCGI 配置。还要核对更具体的前缀 location 是否带有 ^~,使正则匹配被跳过。

若错误来自 PHP-FPM 的 No input file specified,不要仅靠静态 alias 改写就宣布解决。需要另查真实的入口文件及 SCRIPT_FILENAME;本示例没有 PHP 执行配置,也不应把整个应用目录当静态资源暴露。

修改前保留原 location,检查配置后重载实际 Nginx 实例。默认检查示例是:

nginx -t

配置通过不证明磁盘映射和权限正确。重载后用一个已知存在的资源和一个不存在的资源分别检查:前者应返回正确文件,后者应返回 404;还要确认未允许的目录没有因新规则被暴露。异常时恢复旧配置并检查、重载。