文章背景图

Nginx 反代 DDNS 域名后 IP 变化访问失效解决方案

2026-04-09
10
-
- 分钟

Nginx 反代 DDNS 域名后 IP 变化访问失效解决方案

家里 NAS 有公网 IP 但不是固定的,使用 DDNS + 云服务器反代后,每次 IP 变化需要手动 reload nginx 的问题及解决方法。


问题场景

  1. 家里 NAS 有公网 IP,但是动态的(每次重启光猫/路由器就变)
  2. 在 NAS 上配置DDNS,将动态 IP 绑定到域名
  3. 在云服务器上用 1Panel + OpenResty/Nginx 做反向代理
  4. 问题:每次家里 IP 变化后,网站就访问不了了,必须手动 reload nginx 才恢复

原因:Nginx 在启动/重载时会解析域名并缓存 IP 地址,之后一直使用缓存的 IP,不会重新查询 DNS。


问题根源

Nginx 在启动/重载时会解析域名并缓存 IP 地址,之后就一直使用这个缓存的 IP,不会重新查询 DNS。

流程如下:

DDNS 更新 → 域名解析到新 IP → 但 nginx 还在用旧 IP → 访问失败
       ↓
手动 reload nginx → nginx 重新解析域名 → 恢复正常

解决思路:让 nginx 自动重新解析域名,无需手动干预。


解决方案:使用 resolver + 变量

核心原理

Nginx 的 resolver 指令可以配置 DNS 解析器,配合变量使用 proxy_pass 时,会按照 valid 参数指定的时间重新解析域名。

第一步:在 nginx.conf 中添加 resolver

编辑 /usr/local/openresty/nginx/conf/nginx.conf(1Panel 默认使用 OpenResty):

http {
    include mime.types;
    default_type application/octet-stream;
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';
    
    # ... 其他现有配置保持不变 ...
    
    # 添加这两行(在 include conf.d 之前)
    resolver 223.5.5.5 8.8.8.8 valid=30s ipv6=off;
    resolver_timeout 5s;
    
    include /usr/local/openresty/nginx/conf/conf.d/*.conf;
    include /usr/local/openresty/1pwaf/data/conf/waf.conf;
    
    # ... 后续配置 ...
}

参数说明:

参数 说明
223.5.5.5 阿里云 DNS(国内推荐)
8.8.8.8 Google DNS(备用)
valid=30s DNS 缓存有效期 30 秒,超时后重新解析
ipv6=off 禁用 IPv6 解析(避免不必要的查询)

第二步:修改反代配置,使用变量

找到反代配置文件(通常在 /usr/local/openresty/nginx/conf/conf.d/ 目录下),或在 1Panel 中:网站 → 反向代理 → 编辑

修改前:

location ^~ / {
    proxy_pass http://your-ddns-domain.com:port;  # 直接写域名,会缓存 IP
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    # ... 其他配置
}

修改后:

location ^~ / {
    # 用变量存储目标地址
    set $upstream "your-ddns-domain.com:port";
    
    # proxy_pass 引用变量
    proxy_pass http://$upstream;
    
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header REMOTE-HOST $remote_addr;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $http_connection;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Port $server_port;
    proxy_http_version 1.1;
    add_header X-Cache $upstream_cache_status;
    add_header Cache-Control no-cache;
    proxy_ssl_server_name off;
    proxy_ssl_name $proxy_host;
    add_header Strict-Transport-Security "max-age=31536000";
}

关键改动:

  1. set $upstream "your-ddns-domain.com:port";
  2. proxy_pass http://$upstream;

第三步:测试并重载 nginx

# 1. 测试配置语法是否正确
docker exec 1panel-openresty nginx -t

# 2. 重载 nginx 使配置生效
docker exec 1panel-openresty nginx -s reload

如果是 1Panel 直接管理,也可以在面板上点击「重载」按钮。


验证效果

配置完成后,当家里 DDNS 更新 IP 后:

  1. 等待最多 30 秒(valid=30s 设置的时间)
  2. nginx 会自动重新解析域名
  3. 访问恢复正常,无需手动 reload

手动测试方法:

# 在云服务器上查看当前解析的 IP
dig your-ddns-domain.com +short

# 等家里 IP 变化后,再执行一次
dig your-ddns-domain.com +short

# 然后直接访问网站,应该能正常打开
curl -I https://your-proxy-domain.com

其他方案对比

方案 优点 缺点
resolver + 变量(本文方案) 配置一次,自动生效;无需额外脚本 需要修改 nginx 配置
DDNS 更新后 SSH reload 不改 nginx 配置;逻辑简单 需配置 SSH 免密;每次更新都 reload
使用 IP 而非域名 最简单 IP 变化就失效,不实用

推荐度:resolver + 变量 ⭐⭐⭐⭐⭐


常见问题

Q1: valid 时间设多少合适?

  • 30s - 推荐值,平衡响应速度和 DNS 查询频率
  • 10s - 更灵敏,但 DNS 查询更频繁
  • 60s - 减少查询,但 IP 变化后等待时间更长

Q2: 可以用其他 DNS 服务器吗?

可以,常见的有:

  • 阿里云:223.5.5.5
  • 腾讯云:119.29.29.29
  • 114 DNS:114.114.114.114
  • Google:8.8.8.8

Q3: 配置后访问变慢了?

理论上每次请求不会重新解析(有 30 秒缓存),不应该有明显影响。如果确实变慢,检查:

  1. DNS 服务器是否可达
  2. resolver_timeout 是否设置合理(默认 5s)
  3. 云服务器网络是否正常

总结

核心就三步:

  1. nginx.confresolver
  2. 反代配置 用变量 set $upstream + proxy_pass http://$upstream
  3. reload 一次生效

之后 DDNS 更新 IP,nginx 会在 30 秒内自动重新解析。


参考链接:

评论交流

文章目录