Nginx防盗链闭环的核心是日志驱动的精准防护:先自定义日志记录Referer与拦截状态,再用命令筛选高频可疑来源,接着生成可审核的配置建议,最后通过趋势对比实现异常告警。

直接结合 Nginx 日志分析与防盗链配置,能实现从“发现异常”到“快速响应”的闭环,但关键不在全自动拦截,而在用日志驱动精准、低误判的防护策略。核心是:先让日志真实反映 Referer 和拦截行为,再用简单脚本定期识别模式,最后人工校验后更新白名单或限流规则。
第一步:确保日志里能看清谁来了、为什么被拦
默认 access_log 不记录 Referer,也不标记是否触发防盗链。必须自定义日志格式,把关键信息一次性打全:
- 在 http 块中添加:
log_format secure_log '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$blocked"'; - 定义拦截标识变量(放在 server 或 location 内):
set $blocked "-";
if ($invalid_referer) { set $blocked "blocked"; } - 启用该格式日志:
access_log /var/log/nginx/access.log secure_log;
重启后,每条日志末尾会多出两列:Referer 值(如 "https://bad-site.net" 或 "-")和状态("-" 表示放行,"blocked" 表示被 valid_referers 拦截)。
第二步:用命令快速筛出高频可疑来源
不需要写复杂程序,用 Linux 原生命令就能每天定时跑一次,输出前 10 名异常 Referer:
- 只看被拦掉的请求:
awk '$14 == "blocked" {print $11}' /var/log/nginx/access.log | grep -v "^-$" | sort | uniq -c | sort -nr | head -10 - 补充看空 Referer 的高频 IP(常是爬虫或盗链脚本):
awk '$11 == "-" && $14 == "blocked" {print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head -5
结果类似:
247 "https://shop-fake.com"
189 "https://cdn-bad.net"
这些就是优先要处理的盗链站点。
第三步:自动化生成配置建议,不自动上线
把上面结果转成可复制粘贴的 Nginx 配置片段,供运维人工审核后插入 valid_referers —— 这比盲目加黑名单更安全:
- 写个简单 Bash 脚本,读取上一步 top 5 Referer,自动拼出正则白名单项:
echo 'valid_referers none blocked server_names ~\.shop-fake\.com ~\.cdn-bad\.net;' - 若某域名请求量极大且 UA 固定(如 python-requests/2.31),脚本还可建议配合 map 限流:
map $http_user_agent $limit_rate { ~*python-requests 1k; default 0; }
重点:脚本只输出建议,不 reload nginx。所有变更必须经人确认,避免因正则写错或误判正常流量导致大面积 403。
第四步:建立基线,识别“突然变化”才告警
盗链往往不是一直存在,而是某天起流量暴增。用日志统计做趋势对比,比单看绝对值更有效:
- 每天凌晨运行:
awk -v d="$(date -d 'yesterday' +%d/%b/%Y)" '$4 ~ d {print $11}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head -3 > /tmp/referer_yesterday.txt - 对比本周 vs 上周同一天的 top Referer 差异,若某陌生域名从 0 跳到 200+,就发邮件告警。
(可用 diff + mail 命令组合实现)
这样能早于用户投诉发现新盗链源,而不是等带宽被打满才反应。


















