nginx中实现“防盗链+允许特定ip直连”的核心是:用$allow_access变量综合判断referer合法性或ip是否在白名单,再通过return 403拦截未授权请求;需配合geo预处理ip、valid_referers设内置变量,并仅对静态资源location生效。

在 Nginx 中实现“防盗链 + 允许特定 IP 直接访问”,本质是:**对 referer 做限制,但对指定 IP 地址豁免该限制**。不能只靠 valid_referers,必须结合 if 和 $remote_addr 判断,再用变量控制是否放行。
核心思路:用变量标记“是否允许”
先定义一个默认为拒绝的变量(如 $allow_access),然后根据条件(referer 合法 或 IP 在白名单)将其设为 1;最后在 location 中用 deny/allow 或返回状态码控制访问。
配置示例(推荐方式)
以下配置放在 server 或 location 块中:
# 定义白名单 IP(支持多个,用空格分隔)
geo $white_ip {
default 0;
192.168.1.100 1;
203.0.113.45 1;
2001:db8::1 1; # 支持 IPv6
}
<h1>初始化访问权限变量</h1><p>set $allow_access 0;</p><h1>如果是白名单 IP,直接允许</h1><p>if ($white_ip) {
set $allow_access 1;
}</p><h1>如果 referer 合法(例如本站域名或空 referer),也允许</h1><p>valid_referers none blocked server_names *.example.com example.com;
if ($valid_referers) {
set $allow_access 1;
}</p><h1>拒绝未被允许的请求(例如返回 403)</h1><p>if ($allow_access = 0) {
return 403;
}</p>关键细节说明
-
不要在 if 中直接写 allow/deny:Nginx 的
allow/deny不能放在if块里,否则会报错或行为异常;改用return 403或rewrite ... break更可靠。 -
valid_referers 必须在 if 之前声明:它本身不拦截请求,只是设置内置变量
$valid_referers,后续才能在 if 中判断。 -
geo 指令比多次 if 判断 IP 更高效:尤其当白名单 IP 较多时,用
geo预处理可避免重复字符串匹配。 -
注意空 referer 的处理:浏览器直接地址栏输入、HTTPS 页面引用 HTTP 资源等场景可能触发空 referer,若需允许,确保
valid_referers包含none。
补充:仅对特定文件类型启用防盗链
把上述逻辑放在针对静态资源的 location 中,避免影响 API 或后台接口:
location ~* \.(jpg|jpeg|png|gif|webp|pdf|zip|mp4)$ {
# 上述 $allow_access 判断逻辑放在这里
geo $white_ip { ... }
set $allow_access 0;
if (...) { ... }
if ($allow_access = 0) {
return 403;
}
}











