网站迁移时防盗链规则最容易丢,多域名防盗链混乱也没必要买高价商用方案,核心思路是先把散落的规则集中成一份配置,再用统一变量让所有域名共用一套逻辑。这套做法在Nginx、Apache、CDN三层都验证过,下面把操作步骤和坑点一次说清。
为什么规则迁移总是“漏掉”防盗链
做过几次网站迁移的站长应该都有同感:数据库、文件、伪静态规则都检查完了,上线几天后才发现图片外链全红了,这不是粗心,而是防盗链规则本身就散落在多个层级。
迁移前后配置文件的结构差异
旧服务器上,防盗链可能写在三个互不关联的地方:站点conf文件里一段referer判断、全局nginx.conf里一段map映射、还有CDN控制台里单独配置的域名白名单,迁移时如果只搬了站点conf,另外两处就丢了。
行业共识认为,防盗链规则迁移失败的比例之所以居高不下,根因在于规则的三层依赖没有被同时搬走:源站Nginx层、CDN缓存层、应用层程序判断,任何一层缺失,都会造成防盗链“半失灵”有时能限住,有时放行。
多域名场景下参照关系容易断裂
很多时候防盗链规则不是独立生效的,它依赖host、server_name、upstream等变量,迁移后域名指向变了,变量名还沿用旧值,规则就沉默了,典型表现是:新域名下所有图片正常输出,因为referer校验实际没有执行。
多域名防盗链统一管理的前提:搞清楚规则依赖
在动手改配置之前,先想清楚你管理的到底有几个“域”,常见组合有:主站域名、静态资源子域名(img.、static.)、还有可能被第三方调用的开放接口域名。
把域名放进同一张白名单表
统一管理的本质,是让所有域名共享同一份白名单判断,不要在每个server块里单独写valid_referers,那样改一次要动N处,漏一处就出问题。
推荐的做法是在http层或conf.d目录下定义一份独立的防盗链映射表,内容大致如下:
map $http_referer $bad_referer {
default 0;
~baidu.com 0;
~google.com 0;
~ownsite.com 0;
~sub.ownsite.com 0;
~mobile.ownsite.com 0;
}
这份表就是统一管理的“总闸”,后续新增域名时,只需在这一处追加一行正则,然后reload配置即可,所有server块通过判断
$bad_referer变量的值来决定是否返回403。
主域与子域的归属判断
需要注意一个细节:~ownsite.com这类正则默认是模糊匹配,它能命中www.ownsite.com和img.ownsite.com,但不会命中evilownsite.com,因为正则里带了.转义,这是好事,避免误伤。
但如果你的子域名有三级甚至四级,建议写两行精确条目,比如~^https?://[a-z0-9]+.ownsite.com,确保任何子域都放行,同时防止后缀伪装。
规则迁移与多域名防盗链统一管理的具体操作步骤
下面用Nginx作为示例环境,给出从旧服务器迁移规则到新环境,并完成多域名统一管理的完整路径。
第一步:导出并归类现有规则
登录旧服务器,先执行一次全面排查:
- 全局配置文件
nginx.conf里搜valid_referers,记录所有出现位置。 - 每个站点conf文件里搜
referer,记录规则内容。 - 检查CDN控制台,把防盗链白名单截图或导出。
然后把这些规则按类型归入三类:允许域名列表、拒绝空referer策略、特定路径例外,这一步做得好不好,直接决定后续合并的效率。
第二步:合并成统一配置文件
新建/etc/nginx/conf.d/anti_hotlink.conf,把从各处搜集来的白名单域名去重后写入map模块,原配置中如果存在URI级别的例外(比如某些接口需要接受外站调用),单独用if语句挂在特定location内,不要放全局层。
location ~ .(gif|jpg|jpeg|png|webp|bmp|svg)$ {
if ($bad_referer) {
return 403;
}
expires 30d;
}
这样替换之后,所有站点共享同一套白名单和同一套拦截逻辑,而不是每个server块各自为政。
第三步:接入统一管理,避免重复定义
为了让“多域名”真正体现在一套规则里,建议把入口统一收敛到default_server或者专门的静态资源路由上,具体操作方式:
在/etc/nginx/nginx.conf的http块内引入统一配置文件:
include /etc/nginx/conf.d/anti_hotlink.conf;
然后在所有需要防盗链的server块中,只需引用$bad_referer
变量,不再重复书写白名单,这样以后加域名、改白名单,都只动一个文件,reload一次即可,风险点被收敛到最小。
多域名防盗链配置冲突怎么解决
配置冲突是多域名场景下最常见的问题,症状是:A域名下图片正常,B域名下图片全部打不开,但两边用的是同一个配置模板。
冲突的来源:变量覆盖
Nginx的变量作用域是线性的,如果在某个server块里重新定义或修改了$bad_referer的值,会影响后续所有继承该上下文的请求,尤其当多个配置文件同时被include时,出现同名map定义,后者可能覆盖前者。
排查方法很简单:执行nginx -T查看完整展开配置,搜bad_referer出现几次,确认顺序是否符合预期。
冲突的解决:统一入口+最小化局部覆盖
推荐一种组织方式:
| 配置层级 | 内容定位 | 修改频率 |
|---|---|---|
| http层map | 白名单总表 | 低(新增域名时改) |
| server层if判断 | 图片等静态资源拦截 | 中(调整路径规则时改) |
| location层例外 | 特殊接口放行 | 低(仅少数接口需要) |
按照上表分层后,多域名配置冲突的概率会大幅降低,核心原则是:能写在全局的不要写局部,能在map层解决的不要用if解决。
跨域名互相调用的场景处理
如果你的站点之间互相引用资源(比如www调用img),那还需要在map里显式补全所有内部域名,连端口号也要一起写进正则,否则出现http://img.ownsite.com:8080这类带端口的referer时,默认规则可能判定为外部来源。
防盗链规则迁移的常见掉坑点
空Referer的放行策略
大部分浏览器直接输入地址或通过APP内跳转时不带Referer,如果你把空referer一律拦截,会误伤不少真实用户,业内专家指出,空referer拦截通常只适合纯内容站,电商类、社交类站点不建议这么做。
建议策略是:默认放行空referer,但配合IP白名单或User-Agent限制来弥补。
CDN层规则与源站规则叠加后的“双重奏”
很多站点先在CDN配了一层白名单,又在源站Nginx配了一层,迁移时只改了源站,忘了CDN结果就是从CDN回源的请求被源站当成盗链拦掉了,表现为“全站图片裂开”。
操作建议是:迁移期间先在CDN层设置为宽松模式(只记录日志不拦截),确认源站规则正常后再逐步收紧,这样能把故障范围控制在可接受区间。
图片域名和非图片资源的区分
防盗链不是所有静态资源都要套同一套规则,CSS、JS通常不需要referer校验,如果误加了反而会影响第三方统计脚本和支付回调,建议只对图片、视频、安装包这类高消耗资源启用防盗链。
网站迁移防盗链规则丢失怎么办
已经上线了才发现问题,大多数情况是规则表中缺少了主域与资源域之间的对应关系,这时可以拼一个临时兜底方案:
if ($http_referer !~ "^$|自己的域名") { return 403; }
但这只是应急,后续还是要迁移到map统一管理方案,否则下次迁移时会重复踩坑,按照上述方法整理后,下次迁移只需将anti_hotlink.conf和server块引用一并复制到新环境,执行nginx -t验证配置无语法错误后reload即可。
FAQ
网站迁移防盗链规则丢失怎么办
先把旧环境的nginx完整配置导出,搜索所有包含referer或valid_referers的段落,集中放入一个新的map模块,然后在新环境的http层引入该文件,在静态资源location中判断变量并返回403,迁移后测试时记得带上-e参数模拟不同referer来源,验证拦截与放行是否符合预期。
多域名防盗链配置冲突怎么解决
统一在map层维护白名单,所有server块只做变量引用,不重复定义正则规则,当两个域名共用一份资源目录时,把两个域名都加入map的允许列表,避免因为哪一个域名缺失导致误拦截,通过nginx -T可以快速确认最终生效的具体规则来源。
防盗链规则迁移后图片打不开是为什么
多数情况下是False Positive误杀,即规则本身执行了,但白名单里没有包含当前测试域名的完整写法,常见诱因是只写了主域没写子域、协议版本不一致(http与https被视为不同来源)、端口号被正则匹配异常,用curl -I -e "测试来源"逐条比对,很快能定位是哪一层漏掉了对应域名。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/646422.html





