在很多情况下,我们的服务可能会指向一个动态变化的主机名(例如负载均衡后的动态域名,或者容器化环境下的短暂服务 IP)。然而,Nginx 默认会缓存 DNS 解析结果,这会导致动态主机名在 IP 变化后仍然使用旧的 IP 地址,从而导致请求失败。
本文总结了如何配置 Nginx,使其在每次请求时重新解析动态 DNS 主机名。
什么是问题核心?
Nginx 默认在启动时解析 proxy_pass
中的域名并将结果缓存。该解析结果只会在 Nginx 重启或缓存过期后更新。对于动态主机名的场景,这种行为会导致服务不可用,无法跟上 IP 的动态变化。
为了支持动态主机名解析,我们需要让 Nginx 强制在每次请求时重新解析 DNS。
解决方案思路
通过使用以下方法,让 Nginx 实现动态 DNS 主机名解析:
- 借助
resolver
指令:Nginx 配置中必须指定 DNS 解析器。 - 使用变量的动态解析特性:在
proxy_pass
中使用变量,Nginx 会在每次请求时通过 DNS 解析变量对应的域名。 - 控制缓存行为:通过指定
valid
参数,更灵活地控制 Nginx 的 DNS 缓存时间。
配置步骤
1. 基础原理:使用 resolver
和变量
使用 resolver
来配置 Nginx 的 DNS 解析器,并将动态主机名赋值给变量,然后在 proxy_pass
中使用该变量。例如:
http {
resolver 127.0.0.1 valid=30s; # 配置 DNS 解析器
server {
listen 80;
server_name example.com;
location / {
set $backend "dynamic.example.com"; # 动态域名赋值给变量
proxy_pass http://$backend; # 在 proxy_pass 中使用变量
}
}
}
工作原理:
- Nginx 对静态的
proxy_pass
地址只解析一次, - 而对变量
$backend
中的域名,则会在每次请求中重新解析,并通过resolver
进行动态 DNS 查询。
2. 配置 DNS 缓存时间(valid
参数)
在 resolver
指令中,可以增加 valid
参数来控制 DNS 结果的缓存时间。例如:
resolver 127.0.0.1 valid=15s;
- 如果没有配置
valid
参数,将使用 DNS 响应返回的 TTL。 - 例如上述配置会让 Nginx 每隔 15 秒重新解析 DNS。
3. 确保原始路径不丢失
在使用变量 proxy_pass
时,需注意默认行为会覆盖请求的原始路径,因此可以手动保留路径:
set $backend "dynamic.example.com";
proxy_pass http://$backend$request_uri;
$request_uri
:保留用户原本的请求路径。
完整示例
以下是一个完整的 Nginx 配置示例,用于处理动态域名解析:
http {
# 指定 DNS 解析器,支持 IPv4
resolver 127.0.0.1 valid=15s;
server {
listen 80;
server_name my-application.com;
location / {
# 动态分配 DNS 变量
set $backend "dynamic.example.com";
# 代理到动态主机名
proxy_pass http://$backend$request_uri;
# 添加一些 Proxy 配置
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}
注意事项
- 必须配置
resolver
:如果未配置,Nginx 在变量中解析域名时会报错。 proxy_pass
使用变量的影响:一旦使用变量,Nginx 的行为会与静态地址不同,原始请求路径可能会丢失,需手动加$request_uri
保留。- 性能权衡:每次请求都会触发 DNS 解析,会增加一些网络开销。尽量在必要时才开启动态解析。
场景应用与总结
Nginx 默认缓存 DNS 是为了提高性能,但在容器化环境、负载均衡后端地址频繁变化的情况下,静态 DNS 缓存可能导致服务不可用。借助 resolver
和变量配置,Nginx 可以很好地处理动态域名,同时通过 valid
参数合理控制缓存时间以平衡性能和动态性。