在很多情况下,我们的服务可能会指向一个动态变化的主机名(例如负载均衡后的动态域名,或者容器化环境下的短暂服务 IP)。然而,Nginx 默认会缓存 DNS 解析结果,这会导致动态主机名在 IP 变化后仍然使用旧的 IP 地址,从而导致请求失败。

本文总结了如何配置 Nginx,使其在每次请求时重新解析动态 DNS 主机名。


什么是问题核心?

Nginx 默认在启动时解析 proxy_pass 中的域名并将结果缓存。该解析结果只会在 Nginx 重启或缓存过期后更新。对于动态主机名的场景,这种行为会导致服务不可用,无法跟上 IP 的动态变化。

为了支持动态主机名解析,我们需要让 Nginx 强制在每次请求时重新解析 DNS。


解决方案思路

通过使用以下方法,让 Nginx 实现动态 DNS 主机名解析:

  1. 借助 resolver 指令:Nginx 配置中必须指定 DNS 解析器。
  2. 使用变量的动态解析特性:在 proxy_pass 中使用变量,Nginx 会在每次请求时通过 DNS 解析变量对应的域名。
  3. 控制缓存行为:通过指定 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;
        }
    }
}

注意事项

  1. 必须配置 resolver:如果未配置,Nginx 在变量中解析域名时会报错。
  2. proxy_pass 使用变量的影响:一旦使用变量,Nginx 的行为会与静态地址不同,原始请求路径可能会丢失,需手动加 $request_uri 保留。
  3. 性能权衡:每次请求都会触发 DNS 解析,会增加一些网络开销。尽量在必要时才开启动态解析。

场景应用与总结

Nginx 默认缓存 DNS 是为了提高性能,但在容器化环境、负载均衡后端地址频繁变化的情况下,静态 DNS 缓存可能导致服务不可用。借助 resolver 和变量配置,Nginx 可以很好地处理动态域名,同时通过 valid 参数合理控制缓存时间以平衡性能和动态性。