nginx反向代理自定义502/504错误页需四步闭环:开启proxy_intercept_errors、配置error_page跳转、用location = /path { internal; root ... }防套娃、配合proxy_next_upstream实现自动重试兜底。

Nginx 作为反向代理时,后端出错(比如宕机、超时、返回 502/504)默认会直接透传错误或显示简陋的 Nginx 默认页。要实现有容错能力的自定义错误页面,关键不是只换一个 HTML,而是把「拦截 → 替换 → 防套娃 → 可靠兜底」四个环节串起来。
必须开启错误拦截开关
Nginx 默认把后端返回的 502、504 当作“正常响应”直接返回给用户,根本不会触发 error_page。
得在 location 块里显式打开拦截:
location / {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# ? 这行不能少!否则 error_page 对后端错误完全无效
proxy_intercept_errors on;
}
⚠️ 注意:proxy_intercept_errors on 只对 4xx 和 5xx 状态码生效;如果后端返回 200 但内容是错误 HTML,它不处理——那是业务层该解决的问题。
配置对应错误码的跳转路径
在同一个 location 或外层 server 块中写 error_page,指定哪些状态码跳到哪个页面:
error_page 502 504 /maintenance.html; error_page 500 /error.html;
这里 /maintenance.html 是 URI 路径,不是文件系统路径。Nginx 会按 location = /maintenance.html 的规则去定位真实文件。
声明错误页的访问规则(防 404 套娃)
很多人配完 error_page 却看到空白页或又一个 404,就是因为没配 location 块来“放行”这个路径:
location = /maintenance.html {
internal; # ❗禁止外部直接访问,只允许内部跳转
root /usr/share/nginx/html; # 文件实际位置:/usr/share/nginx/html/maintenance.html
}
✅ 要点:
-
internal必加,避免用户手动访问/maintenance.html绕过业务逻辑; -
root路径必须包含该 HTML 文件,且 Nginx 进程有读取权限; - 用
=精确匹配,别写成location /maintenance.html(会误匹配子路径); - 如果用了
alias,注意末尾斜杠:alias /usr/share/nginx/html/;(带斜杠)。
补充容错:让请求自动切到备用后端
仅换页面是被动应对,更进一步可结合 upstream + proxy_next_upstream 实现主动容错:
upstream backend {
server 192.168.1.10:8080 max_fails=2 fail_timeout=30s;
server 192.168.1.11:8080 max_fails=2 fail_timeout=30s;
server 192.168.1.12:8080 backup; # 兜底节点
}
location / {
proxy_pass http://backend;
proxy_intercept_errors on;
error_page 502 504 /maintenance.html;
# ? 出现这些情况时,自动重试下一个 upstream 节点
proxy_next_upstream error timeout http_502 http_504;
proxy_next_upstream_tries 3;
proxy_next_upstream_timeout 30s;
}
✅ 这样一来:
- 后端 A 返回 502 → Nginx 拦截,记一次失败,尝试 B;
- B 也超时 → 再试 C;
- 全失败 → 最终返回
/maintenance.html,而不是裸 502。
验证是否生效的小技巧
- 临时停掉所有后端服务,curl 访问接口:
curl -I http://your-domain.com/api/health
应返回HTTP/1.1 502 Bad Gateway(说明拦截已生效),再访问主页面应看到你的maintenance.html。 - 查看 Nginx error log:
tail -f /var/log/nginx/error.log,确认有没有open() "/usr/share/nginx/html/maintenance.html" failed类报错(路径或权限问题)。 - 用
curl -H "Host: your-domain.com" http://127.0.0.1/maintenance.html测试是否返回 404(说明internal生效);而正常访问/触发错误时能正确加载,就对了。
不复杂但容易忽略。











