宝塔面板 + 高防CDN 源站白名单自动同步:你还在手动加IP?
问题:源站白名单的手动噩梦
高防CDN回源时,源站一般只放行CDN节点IP,防止绕过CDN直接攻击。但CDN节点IP段经常变动(扩容、下线、区域调度),手动维护iptables或宝塔“安全-防火墙”里的IP白名单纯属自虐。某次轻云互联高防CDN的节点池调整,我差点漏放一个新段导致回源失败半小时——这种事不能忍。
解法:宝塔计划任务 + API 动态同步
核心思路:用系统计划任务每隔5分钟调用CDN厂商的API(或官方发布的IP列表URL),解析后写入iptables的ipset集合,再让宝塔防火墙引用该集合。不需要任何第三方插件,纯shell脚本搞定。
第一步:创建ipset集合
ipset create cdn_whitelist hash:net -exist
iptables -I INPUT -m set --match-set cdn_whitelist src -j ACCEPT
iptables -I INPUT -p tcp --dport 443 -j DROP # 拒绝非CDN来源的HTTPS(可选)
注意:宝塔面板默认会把自己的防火墙规则插入到iptables的INPUT链,所以要在宝塔规则的前面插入这个ipset放行规则(优先级检查)。
第二步:编写同步脚本
#!/bin/bash
# /opt/scripts/sync_cdn_whitelist.sh
API_URL="https://api.qingyuncdn.com/v1/ip-list?type=ipv4" # 轻云互联高防CDN的IP列表接口(示例)
TMP_FILE="/tmp/cdn_ip_new.txt"
IPSET_NAME="cdn_whitelist"
# 拉取IP段,格式每行一个CIDR
curl -sS --connect-timeout 10 "$API_URL" | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}/[0-9]{1,2}' > "$TMP_FILE" 2>/dev/null
if [ ! -s "$TMP_FILE" ]; then
logger -t sync_cdn "CDN IP list download failed"
exit 1
fi
# 清空ipset并重新加载
ipset flush "$IPSET_NAME"
while read -r cidr; do
ipset add "$IPSET_NAME" "$cidr" 2>/dev/null
done < "$TMP_FILE"
# 清理临时文件
rm -f "$TMP_FILE"
logger -t sync_cdn "CDN whitelist updated at $(date)"
坑点1:部分CDN API返回的IP可能是域名,需要先用dig +short解析成IP(本例简化,实际生产请处理)。
坑点2:宝塔“安全-防火墙”插件接管iptables后,自己手写的规则可能被其“刷新”操作冲掉。解决办法:将上述iptables命令写入/etc/rc.d/rc.local,并确保宝塔的“放行端口”里不要443——改用上面的iptables DROP策略替代。
第三步:宝塔计划任务配置
宝塔后台 → 计划任务 → 添加Shell脚本:
bash /opt/scripts/sync_cdn_whitelist.sh
执行周期:5分钟(CDN IP变更不频繁,也够用)。
日志查看:可以勾选“输出日志”,或直接grep sync_cdn /var/log/messages。
进阶:配合宝塔Nginx realip模块
光有IP白名单还不够,源站Nginx必须知道真实客户端IP。宝塔默认Nginx编译了ngx_http_realip_module,但在CDN场景下常被忽略。在站点配置的server块中加入:
set_real_ip_from 0.0.0.0/0; # 实际应限制为CDN IP范围,但有了ipset白名单可直接设0.0.0.0/0
real_ip_header X-Forwarded-For;
real_ip_recursive on;
这里set_real_ip_from 0.0.0.0/0看似不安全,但因为前面iptables已经做了源IP白名单,非CDN节点的请求在TCP层就被丢弃了,所以可以信任所有来的请求头部。另一招:如果宝塔防火墙里的“CC防御”开启了,记得把CDN节点IP加到“IP白名单”里,否则可能误拦截。
最后说一句
这套方案我跑在轻云互联一台低配高防服务器上,半年没动过,CDN换节点后自动更新白名单,一次都没断过。比起手动点宝塔面板的“添加IP”舒服太多了。如果你也受困于CDN IP变化,不妨试试——记得先备份iptables规则,出问题可以iptables-restore回滚。