关于 Nginx 反向代理 DDNS 域名,动态 IP 变更后导致502(Bad Gateway)问题。
0x01 前言
Nginx在启动(或重载配置)时,会将反向代理配置中的DDNS域名解析为对应的IP地址并缓存。而DDNS域名的IP是动态变化的,当IP更新后,Nginx不会主动重新解析域名,仍会使用旧的缓存IP,导致请求无法连接到正确的后端服务,最终返回502错误。
0x02 解决方法
定时任务检测+重载Nginx
设置一个定时任务,检测站点存活,如果返回不是200就重启nginx。
#!/bin/bash
# 获取状态码
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" https://itho.cn)
# 判断是否是 200
if [ "$HTTP_CODE" != "200" ]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') 状态码: $HTTP_CODE,正在重启 Nginx..."
nginx -t && nginx -s reload
else
echo "$(date '+%Y-%m-%d %H:%M:%S') 状态正常: $HTTP_CODE"
fi
配置定时任务,每分钟执行一次。
*/1 * * * * /bin/bash /path/to/你的脚本.sh >> /var/log/nginx_ddns_check.log 2>&1
Nginx resolver 方案
- resolver 指定 Nginx 运行时解析域名用的 DNS。
- valid=10s 表示 DNS 结果缓存 10 秒,不是每 10 秒主动查询,而是缓存过期后下次请求重新解析。
- proxy_pass 必须使用变量,例如 $backend_host,这样 Nginx 才会走运行时 DNS 解析。
- 使用 HTTPS 上游时建议加 proxy_ssl_server_name on; 和 proxy_ssl_name 域名;,否则可能出现 SNI 或证书匹配问题。
- 使用变量后,如果要保留原始路径和 query,建议写 $request_uri。
只加 resolver 不够,proxy_pass 必须使用变量,例如 $backend_host,这样 Nginx 才会走运行时 DNS 解析。
valid=10s 不是每 10 秒主动查询 DNS,而是缓存结果最多 10 秒;缓存过期后,下一个请求触发重新解析。
应使用 resolver + 变量 proxy_pass:
resolver 119.29.29.29 valid=10s ipv6=off;
resolver_timeout 5s;
set $backend_host ddns.itho.cn;
location / {
proxy_pass https://$backend_host:8080$request_uri;
proxy_set_header Host ddns.itho.cn;
proxy_ssl_server_name on;
proxy_ssl_name ddns.itho.cn;
}
参考官方文档:
https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass
https://nginx.org/en/docs/http/ngx_http_core_module.html#resolver