背景
今天,我的一个网站突然无法访问,浏览器显示 504 Gateway Time-out,响应头里的 Server 是 openresty。
这类问题通常是反向代理在连接上游时超时。下面把这次完整的排查与修复过程记录下来,便于以后遇到类似问题时快速复盘。
整体架构
用户请求先到域名 A
域名 A 解析到一台 OpenResty 反向代理机器(下文称"代理机")
OpenResty 再把请求转发给
http://域名B:端口,实际就是上游服务所在的机器(下文称"上游机")
这次故障发生在 OpenResty 到上游这一段。
由于服务器用的是自己申请的家宽公网ip,所以运营商不开放80和443端口,而且ip是动态的,会变化
排查过程
1) 先确认上游服务是否正常
在上游机直接访问本地服务端口:
curl -s http://localhost:端口/能看到页面内容,说明上游服务本身没有挂。
2) 再看 OpenResty 的配置
登录代理机后,通过容器方式查看配置:
docker exec 容器名 nginx -T可以看到关键代理配置:
location ^~ / {
proxy_pass http://域名B:端口;
# ...
}3) 关键一步:看 error.log
这次排障最关键的信息来自 OpenResty 的错误日志:
# 在容器内
tail -50 /www/sites/域名A/log/error.log日志里出现了类似这样的报错:
upstream timed out (110: Connection timed out) while connecting to upstream,
client: xx.xx.xx.xx, server: 域名A,
request: "GET /path HTTP/1.1",
upstream: "http://旧IP:端口/path"这里有两个关键点:
OpenResty 把请求代理到了一个旧 IP
这个旧 IP 连不上
4) 做对比验证
在同一台机器里用 getent hosts 或 dig 查询域名 B:
getent hosts 域名B
# 新IP 域名B也就是说,域名 B 当前解析出来的 IP 应该是新IP。
但错误日志里 OpenResty 却去连了旧IP。
这就说明:不是上游挂了,而是 OpenResty 在拿一个旧的解析结果去连。
根因:Nginx 的 DNS 缓存机制
问题的根因就是 proxy_pass 里写了域名,而且没有额外配置 DNS 解析策略。
在默认情况下,像这样的写法:
proxy_pass http://域名B:端口;Nginx/OpenResty 会在启动或 reload 配置时把域名解析成 IP,之后长期使用这个结果。
所以当域名背后的 IP 发生了变化,但 OpenResty 一直拿着旧地址去做连接,自然就会出现 504。
修复方式
方案一:临时重启 OpenResty
docker restart 容器名重启后,Nginx 会重新解析域名,问题通常会立即恢复。
方案二:让 Nginx 每次请求都重新解析 DNS(推荐)
要从根本上解决,需要在代理配置里改成动态解析的方式:
# 原来的写法
proxy_pass http://域名B:端口;
# 修改后的写法
resolver 1.1.1.1 valid=30s;
set $upstream 域名B:端口;
proxy_pass http://$upstream;为什么要这样改:
resolver 1.1.1.1 valid=30s;:指定 Nginx 使用1.1.1.1做 DNS 查询,并且缓存 30 秒set $upstream 域名B:35000;:把目标地址放进变量里proxy_pass http://$upstream;:当proxy_pass使用变量时,Nginx 会在运行时重新解析域名
这样即使域名背后的 IP 再变化,OpenResty 也能较快地切换到新的地址,而不会一直抱着旧 IP 不放。
本次定位问题的关键信息
这次能快速定位,主要是靠两点:
error.log 里的 upstream IP 它直接暴露了 OpenResty 实际连的是哪一个 IP,而不是只告诉你"超时了"。
比对实际 DNS 解析结果 错误日志里连的是旧 IP,但当前 DNS 解析结果是一个新的 IP,这两者不一致,就能判断是 DNS 缓存问题。
这类问题的一般排障顺序
先确认上游服务是否真的在跑
看 Nginx/OpenResty 的 error.log,确认它实际连接的地址和端口
对比当前域名解析结果,确认是否是旧 IP
如果上游是容器,检查容器端口是否正常
如果是 DNS 缓存,考虑改成运行时动态解析
说明
这次不是 OpenResty 本身有 Bug,也不是上游服务直接宕机,而是 Nginx 在 proxy_pass 写域名时的默认缓存行为 引发了故障。
这类问题在生产环境里其实挺常见,尤其是域名背后 IP 发生迁移、切换服务器、或者上游地址调整时。
结论
这次 504 的本质是:
OpenResty 把请求代理到一个旧的上游 IP,导致连接超时。
解决方式也很明确:
临时可以重启 OpenResty;长期建议通过
resolver+set $upstream的方式启用运行时 DNS 解析。
这样就能避免因为域名背后 IP 变化,再次出现类似 504。