如何在Nginx中使用动态DNS而非IP地址配置访问白名单?
这个问题我之前也碰到过,Nginx本身确实不支持直接在allow指令里写动态域名——一方面allow只认IP/IP段,写域名会直接报配置错误;另一方面就算能解析,Nginx也只会在启动或重载配置时把域名解析成IP缓存起来,之后不会自动刷新,完全满足不了动态IP的需求。下面给你两个可行的解决方案,优先推荐第一个,不用折腾额外模块:
方法一:用Geo模块+定时脚本自动更新白名单
这是最通用的方案,利用Nginx原生的geo模块配合定时任务,定期解析动态DNS的IP并更新Nginx配置,然后重载服务。
步骤1:创建动态IP的Geo配置文件
先新建一个专门的配置文件来存储动态IP的判断规则,比如/etc/nginx/conf.d/geo_work_ip.conf:
geo $is_work_ip { default 0; # 这里的IP会由脚本自动生成,初始为空也没关系 }
步骤2:修改虚拟主机配置
在你的站点配置里,用satisfy any来结合固定白名单和动态IP判断(satisfy any表示只要满足任意一个允许条件就放行):
server { # 你的其他配置(监听端口、根目录等)... # 开启"任意条件满足即允许"模式 satisfy any; # 固定IP白名单(原来的静态IP) allow 127.0.0.1; allow 192.168.1.0/24; allow 123.456.789.102/32; deny all; # 动态IP判断:如果是工作IP则允许 if ($is_work_ip = 1) { allow all; } error_page 403 =444; # 其他配置... }
步骤3:编写自动更新IP的脚本
创建一个shell脚本/usr/local/bin/update_work_ip.sh,用来解析动态DNS域名、更新Geo配置并重载Nginx:
#!/bin/bash # 替换成你的动态DNS域名 DDNS_DOMAIN="dansworkip.ddnsfree.com" # 刚才创建的Geo配置文件路径 GEO_CONF="/etc/nginx/conf.d/geo_work_ip.conf" # 安装dig命令(如果没装的话) if ! command -v dig &> /dev/null; then apt update && apt install -y dnsutils fi # 获取动态域名对应的所有IPv4地址 WORK_IPS=$(dig +short $DDNS_DOMAIN | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$') # 备份原配置,防止出错 cp $GEO_CONF ${GEO_CONF}.bak # 重新生成Geo配置内容 echo "geo \$is_work_ip {" > $GEO_CONF echo " default 0;" >> $GEO_CONF for ip in $WORK_IPS; do echo " $ip 1;" >> $GEO_CONF done echo "}" >> $GEO_CONF # 先测试Nginx配置是否合法,没问题再重载 if nginx -t; then systemctl reload nginx echo "$(date): 成功更新工作IP并重载Nginx" >> /var/log/update_work_ip.log else # 如果配置出错,恢复备份 cp ${GEO_CONF}.bak $GEO_CONF echo "$(date): 配置错误,已恢复备份" >> /var/log/update_work_ip.log fi
然后给脚本添加执行权限:
chmod +x /usr/local/bin/update_work_ip.sh
步骤4:设置定时任务自动执行脚本
用crontab -e打开定时任务编辑器,添加一行让脚本每5分钟执行一次(时间间隔可以根据你的IP更新频率调整):
*/5 * * * * /usr/local/bin/update_work_ip.sh >> /var/log/update_work_ip.log 2>&1
保存退出后,定时任务就会自动运行了,最多5分钟就能同步新的工作IP。
方法二:使用Nginx第三方模块(需编译)
如果你的场景需要更实时的IP解析,可以用ngx_http_rdns_module这个第三方模块,它能在每次请求时实时解析域名并匹配。不过这个模块需要你重新编译Nginx,对于Ubuntu系统来说步骤比较繁琐,适合有一定编译经验的用户:
- 先安装编译依赖:
apt install build-essential libpcre3 libpcre3-dev zlib1g zlib1g-dev openssl libssl-dev - 下载对应版本的Nginx源码和
ngx_http_rdns_module模块源码 - 编译Nginx时加上
--add-module=路径/ngx_http_rdns_module参数 - 编译安装后,在配置里用
rdns指令来匹配动态域名:
server { # 其他配置... allow 127.0.0.1; allow 192.168.1.0/24; allow 123.456.789.102/32; rdns on; if ($host ~* dansworkip.ddnsfree.com) { allow all; } deny all; # 其他配置... }
不过这种方法会增加每次请求的延迟(因为要实时解析域名),而且需要维护自定义编译的Nginx,不如第一种方案省心。
备注:内容来源于stack exchange,提问作者DanRan




