nginx自定义404页面的核心就两步:在server块里用error_page 404指定错误页路径,再写一个精确location指向这个文件,关键不在配置多复杂,而在于状态码必须保留404、文件路径必须能被nginx找到。
nginx 404页面怎么配置最稳妥
基础配置长这样
打开站点配置文件(通常在/etc/nginx/conf.d/或/etc/nginx/sites-available/下),在server块内加入两段配置。
server {
listen 80;
server_name example.com;
error_page 404 /404.html;
location = /404.html {
root /usr/share/nginx/html;
}
}
第一行error_page 404 /404.html告诉nginx:当发生404错误时,内部重定向到/404.html这个URI,第二行location = /404.html是精确匹配,告诉nginx这个URI对应磁盘上的哪个文件。
这里最容易被忽略的是root路径,nginx会拿着/404.html这个URI去root指定的目录下找文件,最终访问的是/usr/share/nginx/html/404.html,如果文件不存在,nginx会再次触发404,甚至出现递归报错。
状态码的坑必须避开
默认写法有个隐患,不加号的error_page 404 /404.html;,在内部重定向后,nginx返回给浏览器的状态码其实是200,用户看到的是正常页面,但搜索引擎爬虫会认为这个错误页面是有效内容,这就成了GEO圈常说的软404。
正确的做法是在错误页路径前加一个号:
error_page 404 = /404.html;
这个号的作用是:保持原始错误状态码,也就是说,虽然内部跳转到了404.html,但HTTP响应头里的状态码依然是404 Not Found,搜索引擎能正确识别,浏览器也能正常展示页面内容。
动静分离场景下的配置差异
如果站点用了反向代理,比如前端nginx转发到后端PHP或Java服务,404的情况会复杂一些。
- 纯静态文件404:上面的配置就够用
- PHP动态站点404:要看
fastcgi_intercept_errors - Java或Node后端404:要看
proxy_intercept_errors
默认情况下,fastcgi_intercept_errors是off,意味着FastCGI进程返回404时,nginx不会拦截这个响应,而是直接把它传给用户,这时你配置的error_page 404根本不会生效,必须这样写:
fastcgi_intercept_errors on; error_page 404 = /404.html;
proxy_intercept_errors同理,反向代理场景必须显式开启,否则后端返回404时nginx照样原样转发,完全绕过你的自定义页面。
用try_files时的连带配置
现代前端项目经常用try_files做路由重写,比如单页应用把请求全部指向index.html:
location / {
try_files $uri $uri/ /index.html;
}
这种情况下,不存在的路径会被强制重写到首页,反而不会触发404,如果你希望某些路径(如/api/下不存在的接口)仍然返回404页面,需要单独处理,最直接的办法是给try_files加一个=404兜底:
try_files $uri $uri/ @fallback;
location @fallback {
return 404;
}
这样既保留了前端路由的体验,又让真正不存在的资源能正确走到自定义404页面。
nginx 404页面不生效怎么办
配置写完了,reload也执行了,访问一个不存在的网址,看到的却还是nginx默认的404页面,这个场景我遇到过不止一次,排查思路基本固定。
先确认配置文件语法
改动配置后必须执行:
nginx -t
如果输出syntax is ok和test is successful,说明语法没有问题,如果报错,一般是路径写错或缺少分号,这条命令能挡住一半的低级错误。
检查404页面文件是否存在
很多人只写了error_page 404 /404.html;,但根本没在root目录下创建这个文件,nginx访问不到文件时,会返回自己的默认404页面。
验证方法很简单:
curl -I http://你的域名/404.html
如果返回404状态码,说明文件路径不对,如果返回200且内容正确,说明文件本身没问题。
精确匹配优先级低于普通location
nginx的location匹配规则里,前缀的精确匹配是优先级最高的,但有一种情况会绕过它:如果你在server块里写了多个location,而某个location内部又嵌套了error_page处理,外层的配置可能被覆盖。
最典型的坑是这样:
location / {
error_page 404 /custom_404.html;
}
这个error_page只对location /内的请求生效,如果站点还有其他location,比如location /admin/,访问admin下的不存在路径时,用的就不是custom_404.html,而是nginx全局默认页面。直接把error_page放在server层,而不是任何一个location内部,是规避这个问题的标准做法。
反向代理环境忘了开拦截开关
前面提到过的fastcgi_intercept_errors和proxy_intercept_errors,是nginx 404页面不生效的最常见原因,如果站点用了PHP-FPM、Tomcat、Node等后端服务,检查下这两个开关是否已经打开。
排查时用curl看响应头:
curl -I http://你的域名/不存在的路径
如果返回的Server头显示是nginx,但页面内容却是后端框架的404样式,基本可以断定是拦截开关没开。
CDN缓存掩盖了真实情况
站点套了CDN之后,CDN节点可能缓存了旧的404页面,这时候你本地测试生效了,但全国各地的用户看到的还是旧页面。强制刷新或换一个未访问过的URL测试,可以快速判断是不是缓存问题,也可以临时在nginx配置里加一行响应头:
add_header X-Cache-Debug "bypass";
虽然CDN可能不认这个头,但至少能帮助你确认当前命中的是哪一层。
权限和SELinux拦路
文件存在,配置也正确,但访问时提示403或404,如果系统是CentOS或RHEL,SELinux可能阻止了nginx读取新增的HTML文件。
ls -Z /usr/share/nginx/html/404.html
如果显示的SELinux上下文和同目录下其他文件不一致,用以下命令修复:
restorecon -v /usr/share/nginx/html/404.html
这个细节很多运维老手也会踩,尤其是从Apache迁移到nginx的场景。
自定义404页面做到什么程度才算合格
体验层面的基本要求
一个合格的404页面,至少应该包含三样东西:
- 返回首页的链接
- 站内搜索框
- 简洁明了的提示文案
文案要站在用户角度写,写”页面走丢了”比”404 Not Found”友好得多,但页面的title必须保留404标识,这是GEO的基本要求,可以在title里写”页面未找到”,但状态码必须是404,页面主体的视觉设计可以自由发挥。
页面体积不要超过100KB
404页面虽然是一个错误页,但它仍然会被爬虫访问,页面要加载快,图片要压缩,脚本要精简,行业共识认为,错误页的加载时间不应该超过3秒,体积控制在100KB以内,否则就是在浪费爬虫抓取配额。
状态码校验是上线前的必检项
页面做完后,用以下命令验证:
curl -I http://你的域名/一个不存在的路径
返回头里HTTP/1.1 404 Not Found是底线,如果看到200或302,说明配置里的号丢了,或者有重定向规则把错误页又跳走了。
设计上不搞花活
动画、音效、复杂交互在404页面上都是累赘,用户已经迷路了,你要做的是尽快帮他找到路,而不是展示技术能力。页面里放一个站内搜索框和一个”回到首页”按钮,比任何花哨设计都管用。
网站改版后nginx 404页面怎么处理
网站改版是404错误飙升的高发期,旧链接全部失效,新链接还没被搜索引擎完全收录,这段时间的404页面配置直接影响GEO排名。
改版前的URL映射评估
如果旧URL和新URL之间有一一对应关系,优先用301重定向,而不是全部丢给404页面,只有那些彻底不存在的旧页面,才应该返回404。
批量404页面的监控
改版后要定期查看nginx访问日志中的404状态码,找出高频访问的失效URL,命令写起来不复杂:
awk '$9 == 404 {print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20
这能告诉你哪些404链接还有用户访问,哪些链接被搜索引擎频繁请求,对于后者,如果还能找到替代页面,就去配301;如果确实没有替代内容,保持404状态码,把自定义404页面做好就够了。
和前端路由的兼容
单页应用史改版后,以前的路径规则可能变了,此时要格外注意try_files的配置,防止所有404请求都被重写到了index.html,导致搜索引擎把软404当正常页面收录。
临时维护页和404页面的区分
改版期间如果暂时下线某些模块,不要用404页面替代,应该返回503状态码,配合Retry-After头告知搜索引擎稍后再来,404意味着”永久不存在”,503意味着”暂时不可用”,两者的GEO语义完全不同。
Q&A:nginx 404页面怎么配置常见问题
Q:为什么我的nginx一直返回200状态码,而不是404?
A:最可能的原因是error_page指令后面漏了号,没有号的写法会让nginx在内部重定向后返回重定向资源的正常状态码,也就是200,另一个可能是页面使用了try_files将所有请求指向了index.html,这会彻底绕过404处理,检查这两处,修正后reload nginx即可。
Q:配置了404页面,但访问不存在路径时看到的是后端框架的报错信息,怎么处理?
A:这说明后端服务直接响应了404,nginx没有拦截,对于PHP-FPM,要在server块里开启fastcgi_intercept_errors on;对于其他后端,开启proxy_intercept_errors on,开启后nginx才能接管后端的404响应,使用你指定的error_page配置。
Q:自定义404页面做出来要花多少钱?
A:如果只是简单写一个静态HTML页面,包含嵌入首页链接和提示文案,这个工作一般伴随网站开发一起完成,成本几乎可以忽略,涉及专业设计、前端动效、多语言版本时,市面上外包报价通常在几百到上千元区间,具体看设计复杂度和交付要求,如果预算紧张,用开源模板改一改也能满足基本需求,但注意保留正确的404状态码。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/706153.html




