Nginx 的 secure_link 模块可实现无需后端鉴权的带签名、有时效的私密文件下载;需配置 secure_link 和 secure_link_md5 指令,按规则生成 MD5 签名并校验过期时间与客户端 IP,配合 location 规则控制访问及日志审计。

在 Nginx 中启用 secure_link 模块,可以快速实现带签名、有时效的私密文件下载,无需后端参与鉴权,适合静态资源(如 PDF、视频、安装包)的临时分发场景。
启用 secure_link 模块并配置基础校验
Nginx 默认编译时已包含 secure_link 模块(非动态模块),无需额外加载。关键在于正确设置 secure_link 和 secure_link_md5 指令:
-
secure_link $arg_md5,$arg_expires;:从 URL 查询参数中提取签名(md5)和过期时间(expires) -
secure_link_md5 "$secure_link_expires$uri$remote_addr secret_key";:服务端按约定规则生成期望的 MD5 值,其中$secure_link_expires是解析出的expires参数值,$uri是请求路径,$remote_addr可绑定客户端 IP 防转发,secret_key是自定义密钥(务必保密) - 若签名匹配且
$secure_link_expires > $time_iso8601(即未过期),变量$secure_link值为1;否则为0或空
构建可验证的下载链接(含时间戳与签名)
生成安全链接需严格遵循服务端校验逻辑。例如,要下发 /files/report.pdf,2 小时后过期,服务端密钥为 my_secret_2024:
- 计算过期时间戳(ISO 8601 格式):如当前是
2024-06-15T10:00:00+00:00,2 小时后为2024-06-15T12:00:00+00:00 - 拼接字符串:
2024-06-15T12:00:00+00:00/files/report.pdf192.168.1.100 my_secret_2024(注意:若 Nginx 配置中用了$remote_addr,生成时也必须用相同客户端 IP;测试时可用固定 IP 或去掉该变量) - 取 MD5(小写 32 位):
echo -n "2024-06-15T12:00:00+00:00/files/report.pdf192.168.1.100 my_secret_2024" | md5sum | cut -d' ' -f1 - 最终链接:
https://example.com/files/report.pdf?md5=xxx&expires=2024-06-15T12:00:00%2B00:00
在 location 中拦截并控制访问行为
利用 $secure_link 变量做条件跳转或返回错误:
- 直接返回 403(链接无效或过期):
if ($secure_link = "") { return 403; } - 重写到真实文件路径(推荐):
if ($secure_link = "1") { rewrite ^/files/(.*)$ /real_files/$1 break; },再配合alias或root指向实际存储目录 - 记录审计日志:
log_format secure_download '$remote_addr - $remote_user [$time_local] "$request" $status $secure_link';,便于追溯有效下载
注意事项与常见问题
实际部署中容易踩坑的点:
- 时间格式必须严格一致:Nginx 的
$time_iso8601默认带时区(如+00:00),生成链接时也要用完全相同的格式,建议统一用 UTC 时间避免时区混淆 - URI 编码要处理:URL 中的
+、空格等需编码(如+→%2B),否则 Nginx 解析$arg_expires会出错 - IP 绑定慎用:若用户经代理(如 CDN、LB),
$remote_addr可能是代理 IP,应改用$http_x_forwarded_for并确保可信,或干脆移除 IP 参与签名 - 不支持 GET 参数透传:签名只覆盖
$uri,后续查询参数(如?v=1)不影响校验,但也不参与签名,不可用于携带额外业务字段
secure_link 不依赖外部服务,性能开销极低,适合高并发临时下载场景。只要签名逻辑对齐、时间同步、密钥保密,就能稳定支撑私密分发需求。


















