Nginx中referer模块的静态资源防盗链配置教学
作者:知远漫谈
在当今互联网高速发展的时代,静态资源(如图片、视频、CSS、JS 文件)已成为网站性能优化的核心组成部分。它们承载着视觉表达、交互体验和用户留存的关键任务。然而,随着内容分发网络的普及与资源复用的便捷性,一个令人头疼的问题悄然浮现——静态资源被盗链。
你是否曾见过这样的场景?一个小型博客网站,服务器带宽每月仅 50GB,却因为一张热门图片被多个大型论坛、公众号、甚至电商平台直接嵌入,导致月流量飙升至 500GB,服务器崩溃,账单暴增。这并非科幻小说,而是无数中小站长的真实噩梦。而这一切的根源,正是HTTP Referer 头的滥用。
本文将带你深入 Nginx 的 referer 模块,系统性地掌握防盗链技术的底层原理、实战配置、边界场景处理、Java 后端协同策略,以及如何构建一个安全、高效、可扩展的静态资源防护体系。我们将通过真实代码示例、可视化流程图、多维度测试方案,让你不仅“会配置”,更能“懂原理”、“能优化”、“可扩展”。

什么是盗链?为什么它如此致命?
盗链(Hotlinking),又称“外链引用”或“带宽窃取”,是指第三方网站在未经许可的情况下,直接引用你服务器上的静态资源(如图片、音频、视频)到自己的网页中。
盗链的典型表现
假设你有一个图片资源:https://your-website.com/images/logo.png
某论坛的管理员在帖子中直接写入:<img src="https://your-website.com/images/logo.png" alt="Logo">
当用户访问该论坛时,浏览器会向你的服务器发起请求,加载这张图片。你的服务器承担了:
- 带宽消耗(每访问一次,你就要传输 10KB 图片)
- CPU 资源(处理 HTTP 请求、读取磁盘、发送响应)
- 存储 I/O(频繁读取文件)
- 甚至可能被搜索引擎误判为“重复内容”影响 SEO
而论坛主呢?他零成本获得了高质量视觉内容,提升了页面美观度,还可能因此获得更多点击与广告收入。
盗链的危害
| 危害类型 | 说明 |
|---|---|
| 成本飙升 | 带宽费用呈指数级增长,尤其在云服务商(如阿里云、腾讯云)按量计费下,月支出可能从 50 元暴涨至 5000 元 |
| 性能下降 | 你的服务器资源被大量盗链请求占用,导致合法用户访问变慢,甚至超时 |
| SEO 受损 | 搜索引擎可能认为你的内容被大量复制,降低权重 |
| 安全风险 | 某些盗链者会伪装 Referer,结合 XSS 或 CSRF 攻击,利用你的资源作为跳板 |
Nginx Referer 模块:防盗链的基石
Nginx 本身不直接提供“防盗链”功能,但其强大的 ngx_http_referer_module 模块,允许我们基于 HTTP 请求头中的 Referer 字段进行灵活的访问控制。
什么是 Referer?
Referer 是 HTTP 请求头中的一个字段,用于标识当前请求是从哪个页面跳转而来的。例如:
- 用户从
https://baidu.com点击链接进入你的网站 →Referer: https://baidu.com - 用户直接在浏览器地址栏输入你的 URL →
Referer: (empty) - 用户从微信公众号文章点击图片 →
Referer: https://mp.weixin.qq.com
注意:Referer 字段不是强制的,浏览器可以不发送,或被用户代理(如隐私模式、插件)屏蔽。但它在绝大多数正常场景下是可靠的。
Nginx 防盗链核心指令
| 指令 | 说明 |
|---|---|
valid_referers | 定义合法的 Referer 来源,支持域名、IP、空值等 |
invalid_referer | 可选,用于标记非法 Referer(配合 set 使用) |
return / rewrite | 配合 valid_referers 实现拒绝、重定向、返回占位图等策略 |
工作原理图解(Mermaid)

这个流程图清晰展示了 Nginx 如何基于 Referer 做出决策。每一个判断点都是可配置的,灵活性极高。
防盗链实战配置:从基础到高阶
我们以一个典型电商网站为例,域名:shop.example.com,静态资源部署在 /static/ 路径下,包含图片、CSS、JS、字体等。
基础配置:仅允许本站访问
server {
listen 80;
server_name shop.example.com;
location ~* \.(jpg|jpeg|png|gif|webp|ico|bmp|svg)$ {
valid_referers none blocked shop.example.com www.shop.example.com;
if ($invalid_referer) {
return 403;
}
root /var/www/html;
expires 30d;
add_header Cache-Control "public, immutable";
}
}
配置详解:
valid_referers none blocked shop.example.com www.shop.example.com;
none:允许空 Referer(如用户直接访问图片链接)blocked:允许 Referer 被防火墙或代理屏蔽(值为空或格式异常)shop.example.com和www.shop.example.com:允许这两个域名引用资源
if ($invalid_referer):valid_referers 会自动设置 $invalid_referer 变量,若 Referer 不合法,则值为 1
return 403;:直接拒绝访问,返回 HTTP 403 Forbidden
重要提示:valid_referers 不支持通配符(如 *.example.com),如需泛域名支持,需使用正则表达式(见下文)。
高阶配置:支持泛域名 + 第三方合作站
假设你的品牌授权了 3 家合作伙伴网站:
partner1.compartner2.netmall.example.org
你希望允许这些站点引用你的图片,但拒绝其他所有来源。
location ~* \.(jpg|jpeg|png|gif|webp|ico|bmp|svg)$ {
valid_referers none blocked server_names
*.partner1.com
*.partner2.net
mall.example.org;
if ($invalid_referer) {
return 403;
}
root /var/www/html;
expires 30d;
add_header Cache-Control "public, immutable";
}
解析:
server_names:允许当前 server_name 中的所有域名(即shop.example.com和www.shop.example.com)*.partner1.com:支持子域名泛匹配(如a.partner1.com,b.partner1.com)- ✅ 不支持:
*.com、example.*—— Nginx 不支持通配符在域名中间或结尾
如果你需要更复杂的匹配(如多个顶级域名),请使用正则表达式。
正则表达式:灵活匹配多域名
假设你希望允许:
partner1.compartner2.comcdn.partner3.org- 任何以
mybrand-开头的子域名(如mybrand-shop.com)
location ~* \.(jpg|jpeg|png|gif|webp|ico|bmp|svg)$ {
valid_referers none blocked server_names
~^https?://(www\.)?(partner1|partner2)\.com(/.*)?$
~^https?://cdn\.partner3\.org(/.*)?$
~^https?://mybrand-[^/]+\.com(/.*)?$;
if ($invalid_referer) {
return 403;
}
root /var/www/html;
expires 30d;
add_header Cache-Control "public, immutable";
}
正则说明:
| 表达式 | 说明 |
|---|---|
^https?:// | 匹配 http:// 或 https:// |
(www\.)? | 可选的 www 子域名 |
| `(partner1 | partner2).com` |
(/.*)? | 可选路径(避免因路径不同导致匹配失败) |
cdn\.partner3\.org | 精确匹配,注意转义点 |
mybrand-[^/]+\.com | 匹配 mybrand- 开头 + 任意非斜杠字符 + .com |
正则表达式是 Nginx 防盗链的终极武器,但需注意性能开销。建议仅在必要时使用。
替代方案:返回占位图 vs 重定向 vs 444 关闭连接
方案一:返回 403 Forbidden(最严格)
if ($invalid_referer) {
return 403;
}
- 优点:明确拒绝,符合 HTTP 标准
- 缺点:盗链者可能看到“403”,反而知道你做了防护,可能升级攻击
方案二:返回占位图(推荐!)
location ~* \.(jpg|jpeg|png|gif|webp|ico|bmp|svg)$ {
valid_referers none blocked server_names
~^https?://(www\.)?(partner1|partner2)\.com(/.*)?$;
if ($invalid_referer) {
rewrite ^/(.*)$ /static/hotlink-blocked.png last;
}
root /var/www/html;
expires 30d;
add_header Cache-Control "public, immutable";
}
需提前准备一张占位图:/var/www/html/static/hotlink-blocked.png
优势:
- 对普通用户友好:看到的是“被禁止引用”的提示图
- 对盗链者形成心理威慑:他们无法“偷”你的图,只能看到尴尬的提示
- 可嵌入品牌信息:“本图由 shop.example.com 提供,未经授权禁止引用”
方案三:重定向到首页(温和策略)
if ($invalid_referer) {
return 302 https://shop.example.com;
}
- 适合希望“教育”盗链者,引导其合法合作的场景
- 但可能被搜索引擎收录为“重定向链”,影响 SEO
方案四:返回 444(最隐蔽)
if ($invalid_referer) {
return 444;
}
444是 Nginx 特有状态码,表示“无响应”,直接关闭 TCP 连接- 盗链者完全无法感知,请求被静默丢弃
- 适用于高安全等级、无用户交互的 API 服务
注意:444 会导致浏览器控制台报错 “ERR_EMPTY_RESPONSE”,调试时需谨慎。
防盗链测试:如何验证你的配置是否生效?
方法一:使用 curl 模拟盗链请求
# 正常访问(无 Referer) curl -I https://shop.example.com/images/logo.png # 模拟来自百度的盗链 curl -H "Referer: https://www.baidu.com" -I https://shop.example.com/images/logo.png # 模拟来自自家网站 curl -H "Referer: https://shop.example.com/page.html" -I https://shop.example.com/images/logo.png
观察响应头:
- 若返回
HTTP/2 403→ 防盗链生效 - 若返回
HTTP/2 200→ 配置失败
方法二:使用 Postman / Thunder Client(VSCode 插件)
- 创建 GET 请求:
https://shop.example.com/images/logo.png - 在 Headers 中添加:
- Key:
Referer,Value:https://evil-site.com
- Key:
- 发送请求,观察状态码
方法三:浏览器开发者工具
- 打开 Chrome DevTools → Network
- 刷新页面,找到一张图片请求
- 右键 → “Copy as cURL”
- 在终端中执行,观察响应
方法四:构造 HTML 测试页(本地)
创建一个本地 HTML 文件 test.html:
<!DOCTYPE html>
<html>
<head>
<title>盗链测试页</title>
</head>
<body>
<h1>测试是否被防盗链</h1>
<img src="https://shop.example.com/images/logo.png" alt="测试图" width="300">
</body>
</html>用浏览器打开此文件,观察图片是否加载成功。
建议:将此测试页部署在你的测试域名(如 test.yourdomain.com)上,模拟真实盗链场景。
Java 后端协同:动态生成 Referer 白名单
虽然 Nginx 防盗链强大,但静态配置无法应对动态合作方变更。比如:
- 你接入了 100 个小程序、10 个 H5 平台,每天新增 2~3 个合作方
- 每次修改 Nginx 配置 → 重启服务 → 业务中断
解决方案:Java + Redis + Nginx 动态白名单
我们采用以下架构:
[Java 服务] ←→ [Redis] ←→ [Nginx]
↑ ↑
动态配置 Nginx 读取白名单
Step 1:Java 服务管理白名单(Spring Boot 示例)
@RestController
@RequestMapping("/api/referer")
public class RefererWhitelistController {
@Autowired
private RedisTemplate<String, String> redisTemplate;
// 添加合法域名
@PostMapping("/add")
public ResponseEntity<String> addReferer(@RequestBody String domain) {
if (domain == null || domain.trim().isEmpty()) {
return ResponseEntity.badRequest().body("域名不能为空");
}
// 去除协议头和路径,只保留域名
String cleanDomain = domain.replaceAll("^(https?://)?(www\\.)?", "").split("/")[0];
redisTemplate.opsForSet().add("referer_whitelist", cleanDomain);
return ResponseEntity.ok("已添加: " + cleanDomain);
}
// 获取所有白名单
@GetMapping("/list")
public ResponseEntity<List<String>> getWhitelist() {
Set<String> domains = redisTemplate.opsForSet().members("referer_whitelist");
return ResponseEntity.ok(new ArrayList<>(domains));
}
// 删除域名
@DeleteMapping("/remove")
public ResponseEntity<String> removeReferer(@RequestBody String domain) {
String cleanDomain = domain.replaceAll("^(https?://)?(www\\.)?", "").split("/")[0];
Long removed = redisTemplate.opsForSet().remove("referer_whitelist", cleanDomain);
if (removed > 0) {
return ResponseEntity.ok("已移除: " + cleanDomain);
} else {
return ResponseEntity.notFound().build();
}
}
}Step 2:Nginx 读取 Redis 白名单(需安装 ngx_http_lua_module)
此方案需要 Nginx 编译时启用 lua 模块(如 OpenResty),非标准 Nginx 默认支持。
# nginx.conf
http {
lua_package_path "/usr/local/openresty/lualib/?.lua;;";
init_by_lua_block {
local redis = require "resty.redis"
local red = redis:new()
red:set_timeouts(1000, 1000, 1000)
local ok, err = red:connect("127.0.0.1", 6379)
if not ok then
ngx.log(ngx.ERR, "failed to connect to redis: ", err)
end
-- 预加载白名单
local whitelist, err = red:smembers("referer_whitelist")
if whitelist then
ngx.var.referer_whitelist = table.concat(whitelist, " ")
end
}
server {
listen 80;
server_name shop.example.com;
location ~* \.(jpg|jpeg|png|gif|webp|ico|bmp|svg)$ {
# 动态从 Lua 变量读取白名单
set $valid_referers_list "none blocked server_names $referer_whitelist";
# 由于 Nginx 不支持变量在 valid_referers 中,需使用更高级的 lua 实现
access_by_lua_block {
local referer = ngx.var.http_referer
local whitelist = ngx.var.referer_whitelist
if not referer then
return -- 允许空 Referer
end
-- 解析域名
local domain = string.match(referer, "^[^/]+//([^/]+)")
if not domain then
ngx.exit(403)
end
-- 检查是否在白名单中
local found = false
for d in string.gmatch(whitelist, "[^%s]+") do
if domain == d or string.match(domain, "^%." .. d .. "$") then
found = true
break
end
end
if not found then
ngx.log(ngx.WARN, "Blocked hotlink from: ", domain)
ngx.exit(403)
end
}
root /var/www/html;
expires 30d;
add_header Cache-Control "public, immutable";
}
}
}
- 优势:无需重启 Nginx,Java 服务更新 Redis,Nginx 实时生效
- 缺点:依赖 OpenResty,运维复杂度上升
适用场景对比表
| 方案 | 适用场景 | 是否需重启 Nginx | 维护成本 | 推荐指数 |
|---|---|---|---|---|
| 静态配置 | 合作方固定(<5 个) | 是 | 低 | ⭐⭐⭐⭐ |
| 正则表达式 | 多域名、子域名 | 是 | 中 | ⭐⭐⭐⭐ |
| 占位图 + 静态 | 通用网站、电商 | 是 | 低 | ⭐⭐⭐⭐⭐ |
| Redis + Lua | 动态合作、SaaS 平台 | 否 | 高 | ⭐⭐⭐⭐ |
防盗链 + CDN 混合部署:最佳实践
大多数企业都会使用 CDN(如阿里云 CDN、Cloudflare)加速静态资源。但 CDN 会改变 Referer 的来源!
错误做法
valid_referers shop.example.com; # 仅允许本站
当你把图片托管在 CDN(如 https://cdn.shop.example.com)时,用户从 shop.example.com 访问,请求的 Referer 是 shop.example.com,但CDN 回源时的 Referer 是 CDN 的域名!
结果:CDN 回源失败 → 图片无法加载!
正确做法:CDN 防盗链 + 源站双重防护
方案:源站只允许 CDN 回源,CDN 层做用户访问控制
用户 → CDN → (回源) → Nginx 源站
Nginx 源站配置(仅允许 CDN IP):
# 限制仅允许 CDN 回源访问
location ~* \.(jpg|jpeg|png|gif|webp|ico|bmp|svg)$ {
# 仅允许阿里云 CDN IP 段(示例)
allow 101.226.0.0/16;
allow 101.227.0.0/16;
deny all;
# 不检查 Referer,因为回源是 CDN 发起的
root /var/www/html;
expires 30d;
}
CDN 防盗链配置(以阿里云 CDN 为例):
- 登录控制台 → CDN → 选择域名 → 防盗链
- 选择“黑白名单模式”
- 白名单填:
https://shop.example.com/* - 启用“忽略查询参数”(避免 ?v=123 被拦截)
- 启用“Referer 空值允许”
这样,只有从你官网跳转的请求才能通过 CDN 加载图片,而 CDN 回源不受限制。
实际 CDN 防盗链配置示例(阿里云)
| 项目 | 配置值 |
|---|---|
| 防盗链类型 | 白名单 |
| 白名单内容 | https://shop.example.com/* |
| 是否允许空 Referer | ✅ 是 |
| 是否忽略查询参数 | ✅ 是 |
| 是否开启 Referer 优先级 | ✅ 是 |
重要:CDN 防盗链规则比 Nginx 更高效,因为它在边缘节点就拦截,节省了回源带宽!
特殊场景处理:微信、抖音、App 内嵌浏览器
微信公众号、抖音、快手、微博等 App 内嵌浏览器,默认不发送 Referer,或发送 https://mp.weixin.qq.com。
问题:你的防盗链配置阻止了微信公众号中的图片显示!
valid_referers shop.example.com www.shop.example.com;
微信公众号访问你的图片 → Referer: https://mp.weixin.qq.com → 被拦截 → 图片空白!
解决方案:
location ~* \.(jpg|jpeg|png|gif|webp|ico|bmp|svg)$ {
valid_referers none blocked
shop.example.com www.shop.example.com
mp.weixin.qq.com
douyin.com
kuaishou.com
weibo.com;
if ($invalid_referer) {
return 403;
}
root /var/www/html;
expires 30d;
add_header Cache-Control "public, immutable";
}
微信公众号的 Referer 是 https://mp.weixin.qq.com,不是 mp.weixin.qq.com,请确保包含协议头!
更安全的做法:使用正则匹配微信域名
valid_referers none blocked server_names
~^https?://(www\.)?(shop\.example\.com|mp\.weixin\.qq\.com|douyin\.com|kuaishou\.com|weibo\.com)(/|$);
小贴士:如何获取真实 Referer?
在微信公众号文章中插入一张图片,然后:
- 手机微信 → 长按图片 → “在浏览器中打开”
- 打开开发者工具 → Network → 查看图片请求的 Referer
- 将其加入白名单
防盗链的边界与陷阱
陷阱一:误封搜索引擎爬虫
百度、Google 爬虫抓取你的图片用于图片搜索,它们的 Referer 是空的或伪装的。
valid_referers none blocked server_names;
正确做法:允许空 Referer (none),这是搜索引擎的默认行为。
陷阱二:移动端 App 无 Referer
许多原生 App(如 iOS/Android)使用 URLConnection 或 OkHttp 请求图片,默认不带 Referer。
解决方案:
- 为 App 设置自定义 Header(如
X-App-Version),后端校验 - 或者:对 App 资源单独部署路径,如
/app-images/,不启用防盗链
location ~* ^/app-images/ {
# 不做防盗链,由 App 通过 Token 鉴权
root /var/www/html;
expires 30d;
}
location ~* \.(jpg|jpeg|png|gif|webp)$ {
# 仅对网站图片启用防盗链
valid_referers none blocked server_names;
if ($invalid_referer) { return 403; }
root /var/www/html;
expires 30d;
}
陷阱三:HTTPS 跨域 Referer 丢失
当你的网站是 https://shop.example.com,而引用者是 http://blog.com(HTTP),浏览器出于安全策略,不会发送 Referer。
解决方案:
- 所有合作方必须使用 HTTPS
- 使用
Referrer-Policy控制 Referer 发送策略(在 HTML<head>中):
<meta name="referrer" content="strict-origin-when-cross-origin">
推荐策略:strict-origin-when-cross-origin,在跨域时只发送协议+域名,不暴露路径
性能与安全权衡:防盗链的代价
性能影响分析
| 配置方式 | CPU 开销 | 内存开销 | 响应延迟 |
|---|---|---|---|
| 静态域名 | 极低 | 无 | 0ms |
| 正则表达式 | 中 | 低 | 1~5ms |
| Lua + Redis | 高 | 中 | 5~20ms |
| CDN 防盗链 | 极低 | 无 | 0ms(边缘节点) |
推荐组合:CDN 防盗链(主) + Nginx 静态白名单(辅) + 占位图兜底
安全性对比
| 方案 | 抗伪造能力 | 抗绕过能力 | 推荐度 |
|---|---|---|---|
| 静态域名 | 中 | 低 | ⭐⭐⭐ |
| 正则表达式 | 高 | 中 | ⭐⭐⭐⭐ |
| Lua + Redis | 极高 | 高 | ⭐⭐⭐⭐⭐ |
| 444 关闭 | 极高 | 极高 | ⭐⭐⭐⭐ |
防盗链不是万能的:恶意用户可通过代理、伪造 Referer(如使用 curl -H "Referer: shop.example.com")、使用爬虫工具(如 Puppeteer)绕过。
真正的安全应是:防盗链 + Token 鉴权 + IP 限速 + 日志监控
监控与日志:如何发现盗链行为?
Nginx 日志增强
修改 nginx.conf 的 log_format:
log_format hotlink '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" "$http_user_agent" '
'$invalid_referer';
access_log /var/log/nginx/access.log hotlink;
日志分析脚本(Python)
import re
from collections import Counter
with open('/var/log/nginx/access.log') as f:
lines = f.readlines()
hotlink_count = Counter()
for line in lines:
if '"-" ' in line or ' 403 ' in line:
match = re.search(r'(\S+) - - \[.*\] "GET .*" 403 (\d+) "([^"]+)"', line)
if match:
referer = match.group(3)
if referer != '-' and not referer.startswith('https://shop.example.com'):
hotlink_count[referer] += 1
print("Top 10盗链来源:")
for ref, count in hotlink_count.most_common(10):
print(f"{count:4d} 次 | {ref}")输出示例:
Top 10盗链来源:
2845 次 | https://evil-site.com
1987 次 | https://forum.example.org
892 次 | https://t.me
345 次 | https://twitter.com
每周运行一次,发现异常来源,及时加入黑名单!
防盗链之外:更高级的资源保护方案
方案一:Token 鉴权(适用于敏感资源)
location ~* ^/private/ {
# 生成临时 token,有效期 5 分钟
set $token $arg_token;
if ($token = "") {
return 403;
}
# 校验 token 是否合法(可结合 Lua + Redis)
access_by_lua_file /etc/nginx/check_token.lua;
root /var/www/html;
}
Java 生成 Token:
@GetMapping("/image/{id}/token")
public ResponseEntity<String> generateImageToken(@PathVariable String id) {
String token = UUID.randomUUID().toString().replace("-", "");
redisTemplate.opsForValue().set("token:" + token, id, Duration.ofMinutes(5));
return ResponseEntity.ok("https://shop.example.com/private/" + id + "?token=" + token);
}方案二:签名 URL(类似阿里云 OSS)
https://shop.example.com/images/photo.jpg?Expires=1728000000&Signature=abc123&OSSAccessKeyId=key123
Java 签名逻辑(伪代码):
String sign = HMACSHA256(secretKey, "GET&/images/photo.jpg&Expires=1728000000");
Nginx 验证签名(需 Lua):
-- 检查 Expires 是否过期
-- 检查 Signature 是否匹配
-- 检查 OSSAccessKeyId 是否合法
方案三:WebP + 自适应格式 + 懒加载
- 将 JPG 转为 WebP(体积减少 30%~50%)
- 使用
<picture>标签,浏览器自动选择格式 - 图片懒加载,减少初始请求数
<picture> <source srcset="/images/photo.webp" type="image/webp"> <source srcset="/images/photo.jpg" type="image/jpeg"> <img src="/images/photo.jpg" alt="Photo" loading="lazy"> </picture>
既能提升体验,又能减少盗链价值(盗链者拿到的是 WebP,兼容性差)
最佳实践总结
- HTTPS 站点必须要求合作方也使用 HTTPS,否则 Referer 会被浏览器屏蔽
- 优先使用 CDN 防盗链,Nginx 仅做兜底
- 白名单必须包含
none和blocked,避免搜索引擎和 App 无法访问 - 微信、抖音、微博等平台 Referer 必须显式加入白名单
- 避免使用正则表达式,除非必须;静态域名性能更高
- 使用占位图而非 403,提升用户体验
- 对 App 资源使用独立路径,不启用防盗链
- 日志监控 + 每周分析盗链来源,动态更新白名单
- 禁止使用
valid_referers匹配*.com,Nginx 不支持 - 防盗链 ≠ 安全,敏感资源需结合 Token、签名、限速
最终推荐配置模板(开箱即用)
server {
listen 80;
server_name shop.example.com;
# 静态资源防盗链配置
location ~* \.(jpg|jpeg|png|gif|webp|ico|bmp|svg|css|js|woff|woff2|ttf|eot)$ {
valid_referers none blocked server_names
shop.example.com www.shop.example.com
mp.weixin.qq.com douyin.com kuaishou.com weibo.com;
if ($invalid_referer) {
rewrite ^/ /static/hotlink-blocked.png last;
}
root /var/www/html;
expires 365d;
add_header Cache-Control "public, immutable";
add_header Vary Accept-Encoding;
}
# 占位图单独放行(避免循环重定向)
location = /static/hotlink-blocked.png {
root /var/www/html;
expires 7d;
add_header Content-Type image/png;
}
# 其他静态资源
location / {
root /var/www/html;
try_files $uri $uri/ =404;
}
}
- 将
hotlink-blocked.png放入/var/www/html/static/,并确保其权限可读 - 重启 Nginx:
sudo nginx -t && sudo nginx -s reload
附录:防盗链配置自查清单
| 检查项 | 是否完成 |
|---|---|
已允许空 Referer (none) | ☑️ |
已允许被屏蔽 Referer (blocked) | ☑️ |
| 已包含自有域名 | ☑️ |
| 已包含微信、抖音等平台域名 | ☑️ |
| 已测试本地 HTML 引用 | ☑️ |
| 已测试 curl 模拟盗链 | ☑️ |
| 已配置占位图而非 403 | ☑️ |
已启用缓存头 expires 和 Cache-Control | ☑️ |
| 已排除 App 资源路径 | ☑️ |
| 已部署日志监控脚本 | ☑️ |
到此这篇关于Nginx中referer模块的静态资源防盗链配置教学的文章就介绍到这了,更多相关Nginx referer静态资源防盗链内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
