nginx的resolver不是动态dns,而是反向代理层的有限dns缓存机制;必须置于http块顶层并配valid=参数,配合变量proxy_pass或upstream resolve才能触发动态解析,否则仍静态解析一次。

Linux 中“动态域名解析”不是单一技术,而是根据场景分三类:本地静态映射(/etc/hosts)、系统级 DNS 转发(如 dnsmasq)、或向公网 DNS 服务商推送 IP 变更(如 DNSPod)。选错类型会导致配置无效——比如用 hosts 文件去应对家庭宽带 IP 每天变一次的场景,根本起不到“动态”作用。
什么时候该改 /etc/hosts?
只适用于开发测试、内网固定主机名绑定、或临时屏蔽域名。它不“动态”,只是你手动改完就生效,系统优先读它,但不会自动感知 IP 变化。
- 必须用 root 权限编辑:
sudo nano /etc/hosts或sudo tee -a /etc/hosts - 格式严格:一行一条,
IP地址 域名 [别名],中间用**至少一个空格**分隔,不能用制表符或逗号 - 常见错误:
127.0.0.1 www.example.com看似正常,但若前后有不可见 Unicode 字符(比如从网页复制粘贴),getent hosts www.example.com会返回空 - 改完不生效?先执行
getent hosts www.example.com验证,再试ping -c1 www.example.com;如果仍不对,检查是否被systemd-resolved或nscd缓存——sudo systemd-resolve --flush-caches或sudo systemctl restart nscd
为什么 dnsmasq 是本地动态解析最稳的选择?
当你需要在局域网内让多台机器通过域名访问一台经常换 IP 的设备(比如树莓派、NAS),又不想依赖外部 DNS,dnsmasq 就是唯一合理方案。它支持基于 DHCP 分配结果自动写入 DNS 记录,也支持手动配置 address=/domain/ip 规则。
- 必须先停掉
systemd-resolved,否则端口 53 冲突:sudo systemctl disable --now systemd-resolved,再sudo rm -f /etc/resolv.conf && echo "nameserver 127.0.0.1" | sudo tee /etc/resolv.conf -
dnsmasq默认不读/etc/hosts,要启用需加配置项:addn-hosts=/etc/hosts(否则你改了hosts它也不认) - 想让
dnsmasq自动响应dev.local类域名?加这行:address=/dev.local/192.168.1.100,然后sudo systemctl restart dnsmasq - 验证是否工作:
dig @127.0.0.1 dev.local +short应返回 IP;如果超时,检查防火墙是否放行 UDP 53:sudo ufw allow 53/udp
需要把家里服务器暴露到公网?别碰 named,直接上 DNSPod 脚本
自己搭 BIND 做 DDNS 是上世纪做法。现在主流是调用 DNSPod、阿里云、Cloudflare 的 API,由脚本定时检测本机公网 IP 并更新记录。关键不是“怎么写脚本”,而是“怎么避免重复更新和权限泄露”。
- API Token 必须存进文件并设权限:
chmod 600 ~/.dnspod-cred,内容仅两行:ID=xxx和TOKEN=yyy,脚本里用source ~/.dnspod-cred加载 - 不要每分钟跑一次更新:IP 不变时频繁调 API 可能触发限流。应先比对当前记录值与本机 IP:
curl -s "https://dnsapi.cn/Record.List?login_token=${ID},${TOKEN}&format=json&domain_id=${DOMAIN_ID}&sub_domain=${SUB}" | jq -r '.records[0].value' - IPv6 场景下,务必用
AAAA记录类型,并用ip -6 addr show eth0 | grep 'inet6.*global' | head -1 | awk '{print $2}' | cut -d'/' -f1提取地址,别用curl ifconfig.co(它可能只返回 IPv4) - 加进 crontab 时用绝对路径:
*/10 * * * * /home/user/ddns.sh >> /var/log/ddns.log 2>&1,避免环境变量缺失导致jq或curl找不到
Nginx 的 resolver 不是“动态 DNS”,它是反向代理层的特殊缓存机制
很多人以为在 Nginx 里配了 resolver 就能自动适应后端 IP 变更,其实它只解决 upstream server 域名的首次解析和有限缓存,不处理故障转移、不轮询多 IP、不重试失败查询——全靠你手动补全逻辑。
-
resolver必须写在http块顶层,写在server或upstream里会报"resolver" directive is not allowed here -
valid=30s是生死线:设成300s意味着后端切 IP 后,Nginx 会持续发请求到已下线的旧地址长达 5 分钟 - upstream 中的
server必须带端口:server api.example.com:8080 resolve;,写成server api.example.com resolve;直接报错 - 真要容错?光靠
resolve不够,必须加:proxy_next_upstream error timeout http_502 http_503 http_504;,且确保后端 DNS 返回多个 A 记录(单 IP 时这条没用)
真正容易被忽略的是:所有这些“动态”方案都依赖时间准确性。NTP 不同步,systemd-resolved 的 DNSSEC 验证会失败,DNSPod API 签名会过期,dnsmasq 的 TTL 计算也会错乱。运行前先确认 timedatectl status 显示 System clock synchronized: yes。











