nginx配置404优雅页面需确保三要素:error_page作用域正确、proxy_intercept_errors或fastcgi_intercept_errors开启、错误页路径真实可读且加internal保护。

在 Nginx 中配置 404 优雅页面,核心不是“加一行 error_page 就完事”,而是确保三个关键环节全部到位:指令作用域正确、错误拦截开关开启、错误页路径真实可读且受保护。
error_page 指令必须放在生效的作用域里
它可写在 http、server 或 location 块中,但实际是否触发,取决于错误来源和匹配路径:
- 静态文件 404(如访问 /missing.css):写在 server 块或匹配该路径的 location 块内都有效
- 反向代理后端返回 404(如 proxy_pass 到 Node.js 或 Django):必须在同级 location 块中启用 proxy_intercept_errors on,否则 Nginx 默认透传状态码,不走本地 error_page
- PHP-FPM 返回 404:需在 http 或对应 server 块中设置 fastcgi_intercept_errors on
- 不要把 error_page 404 /404.html 写在 location /api { ... } 这类子路径块里——它只对 /api 下产生的 404 生效,主站其他路径仍走默认页
错误页资源路径要绝对可靠
root 是拼接路径的基准,不是完整路径。例如:
root /var/www/error-pages; + location = /404.html → 实际查找 /var/www/error-pages/404.html
- 确认文件存在:
ls -l /var/www/error-pages/404.html - 确保 Nginx worker 进程(如 www-data 用户)有读权限:
chmod 644 /var/www/error-pages/404.html - 父目录要有执行权限(允许进入):
chmod 755 /var/www/error-pages - 强烈建议加 internal,防止用户直接访问 /404.html(比如手动输入这个 URL)
- 别用 alias 替代 root —— 对
location = /404.html这种精确匹配,alias 容易导致路径错位,root 更稳
典型配置示例(含常见变体)
一个能落地的 server 块片段:
server {
listen 80;
server_name example.com;
root /var/www/html;
<pre class="brush:php;toolbar:false;"># 主站 404 处理
error_page 404 /404.html;
# 静态资源缺失时也走 try_files fallback(可选增强)
location / {
try_files $uri $uri/ /index.html;
}
# 错误页专用 location,必须 internal + root 明确
location = /404.html {
internal;
root /var/www/error-pages;
}
# 若使用反向代理,需在此 location 内开启拦截
location /api/ {
proxy_pass http://backend;
proxy_intercept_errors on;
error_page 404 = @api_404;
}
location @api_404 {
return 302 /fallback;
}}
- 注意:error_page 后面的路径是 URI,不是文件系统路径;root 指令才决定文件系统查找起点
- 若想让 404 页面返回 200 状态码(少见但有时用于 SEO 或埋点),可写成
error_page 404 =200 /404.html - 多个错误码可合并配置:
error_page 404 500 502 /error.html
验证与调试要点
配完别急着重启,先做这几步:
- 语法检查:
nginx -t - 确认 Nginx 已重载:
nginx -s reload - 用 curl 测试响应头:
curl -I https://example.com/this-page-does-not-exist,看是否返回 404 状态码 + 正确 Content-Type - 故意访问一个不存在的静态文件(如 /nonexistent.jpg),观察是否显示自定义页而非默认 Nginx 404
- 如果是代理场景,可临时让后端返回 404(如访问一个不存在的 API 路径),验证是否被拦截并跳转











