Nginx反向代理Node.js时,静态资源防盗链必须由Nginx在本地服务阶段通过valid_referers拦截,而非交由Node.js处理;需将/uploads/、/static/等路径用alias剥离代理,配置Referer白名单并注意none、blocked及子域覆盖。

Nginx 为 Node.js 应用做反向代理时,静态图片与文件的防盗链不能放在 Node.js 层处理——应由 Nginx 在文件服务阶段直接拦截,既高效又可靠。核心是把静态资源路径(如 /uploads/、/static/、/images/)从代理逻辑中剥离,交由 Nginx 本地 root 或 alias 服务,并在此 location 块内配置 Referer 白名单。
静态资源路径必须独立于 proxy_pass
Node.js 通常只处理动态请求(如 /api/、/login),而图片、上传文件、前端构建产物等应避免经由 Node.js 中转。否则:
- 增加 Node.js 负载和内存压力
- 无法利用 Nginx 的高效缓存与防盗链机制
-
valid_referers在 proxy 场景下无效(它只对本地文件服务生效)
✅ 正确做法:
server {
listen 80;
server_name example.com;
# ✅ 静态资源走本地文件系统,不进 Node.js
location ^~ /uploads/ {
alias /var/www/myapp/uploads/;
expires 7d;
add_header Cache-Control "public, immutable";
# 防盗链开始
valid_referers none blocked example.com *.example.com cdn.example.com;
if ($invalid_referer) {
return 403;
}
}
location ^~ /static/ {
alias /var/www/myapp/dist/static/;
expires 1y;
add_header Cache-Control "public, immutable";
valid_referers none blocked example.com *.example.com;
if ($invalid_referer) {
return 403;
}
}
# ❌ 其他所有请求才交给 Node.js
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}⚠️ 注意:
alias末尾不加/时,路径映射需严格对应;^~前缀比正则更高效,适合前缀型静态路径。
白名单要覆盖真实访问来源
盗链拦截失效,90% 出在白名单漏配。常见必须项:
-
none:允许用户直接输入图片 URL、微信内嵌页、小程序、书签访问 -
blocked:兼容 HTTPS 页面引用 HTTP 资源、隐私模式、企业防火墙清空 Referer -
example.com和www.example.com:视为两个不同字符串,都要写上 -
*.example.com:覆盖cdn.example.com、assets.example.com等子域 - 若用了 CDN(如 Cloudflare、阿里云 DCDN),确保 CDN 域名也在白名单中,或关闭其 Referer 透传(改用
X-Forwarded-For+ IP 限流补强)
避免防盗链误伤 Node.js 渲染的页面
有些项目用 Node.js SSR(如 Next.js、Nuxt),HTML 里 <img src="/uploads/xxx.jpg"> 是合法的,但防盗链可能因 Referer 是 http://localhost:3000(开发环境)或缺失(SSR 渲染无 Referer)而拦截。
解决方法:
- 生产环境确保 HTML 页面域名与白名单一致(如
https://example.com) - 开发环境可临时加
valid_referers none blocked localhost:3000 127.0.0.1:3000; - 更稳妥:将上传资源路径设为独立二级域(如
https://assets.example.com/xxx.jpg),单独配 DNS + SSL + 防盗链,彻底解耦
高风险场景建议叠加 secure_link
仅靠 Referer 可被伪造,对会员头像、商品原图、下载附件等敏感静态文件,推荐启用 secure_link:
location ^~ /private/images/ {
secure_link $arg_token,$arg_expires;
secure_link_md5 "my_secret_key$uri$arg_expires";
if ($secure_link = "") { return 403; }
if ($secure_link = "0") { return 410; } # 过期
alias /var/www/myapp/private/images/;
}Node.js 后端生成链接时,需按相同规则拼接 token(URI 不带参数、时间戳为秒级整数)。这样即使 URL 泄露,也仅限时有效、不可重放。
测试是否生效
配置后重载:nginx -t && nginx -s reload
终端快速验证:
# 应返回 200(合法 Referer) curl -H "Referer: https://example.com" https://example.com/uploads/test.jpg # 应返回 403(非法 Referer) curl -H "Referer: https://bad-site.com" https://example.com/uploads/test.jpg # 应返回 200(无 Referer,即直接访问) curl https://example.com/uploads/test.jpg


















