最安全做法是将备份目录移出Web根目录,并通过带权限校验的下载脚本(如PHP/Python)控制访问,避免Nginx直接暴露备份文件;若必须放在Web下,则用location ^~ /backup/ { deny all; }严格拦截或配合auth_basic基础鉴权。
nginx 配置 location 拦截备份目录访问
数据库备份目录(比如 /backup/ 或 /data/db-backup/)一旦放在 web 根目录下,又没做限制,直接访问 https://example.com/backup/20240512.sql 就能下载,等于把钥匙挂门口。最直接的办法是用 location 块拒绝所有对该路径的请求。
- 在 server 块里加:
location ^~ /backup/ { deny all; } -
^~表示前缀匹配且优先级高于正则,避免被后续location ~ \.sql$之类规则意外绕过 - 别只写
location /backup—— 缺少末尾/会导致匹配到/backup-logs/这类路径失效 - 如果备份目录不在 Web 根下(推荐做法),这步其实可以跳过;但很多人图省事放进了
html/里,那就必须拦
用 auth_basic 做基础鉴权(适合内部管理入口)
有些场景需要临时开放下载权限,比如运维从浏览器手动拉一个备份,又不想暴露给所有人。这时 auth_basic 是轻量、够用的选择,但别指望它防住自动化扫描或撞库。
- 生成密码文件:
htpasswd -c /etc/nginx/auth.db backup-user
- 配置段示例:
location ^~ /backup/ { auth_basic "DB Backup Area"; auth_basic_user_file /etc/nginx/auth.db; alias /var/backups/mysql/; } -
alias必须用,不能用root:否则请求/backup/2024.sql会拼成/var/backups/mysql/backup/2024.sql,多了一层路径 - 注意 Nginx 用户(通常是
www-data或nginx)要有读取/var/backups/mysql/和/etc/nginx/auth.db的权限,否则返回 403 不是密码错,而是文件打不开
Referer 和 UA 防盗链对备份文件基本无效
网上常见用 valid_referers 拦 SQL 文件下载,但这对备份目录完全不适用。原因很实在:
- 备份文件通常不是通过网页超链接触发下载,而是用户直接粘贴 URL 或用 curl/wget 批量抓取
-
Referer可被任意伪造,curl -e "https://google.com" https://x.com/backup/1.sql一试就穿 - 浏览器下载时 Referer 可能为空(比如地址栏直输),导致合法用户也被拒
- 真正要防的是「未授权访问」,不是「来源是否网页」——该用鉴权,别用防盗链凑数
更安全的做法:把备份移出 Web 目录 + 用脚本控制下载
所有配置层的防护都是补救措施。最省心也最可靠的方式,是让备份压根不在 Nginx 能 serve 的路径里。再配合一个带权限校验的下载脚本,可控性高得多。
- 备份存到
/var/backups/mysql/(非/var/www/html/下),Nginx 默认根本访问不到 - 写一个 PHP/Python 脚本(如
/var/www/html/download-backup.php),用readfile()或send_file()输出文件,但先校验 session、token 或 IP 白名单 - 脚本里务必用
basename($_GET['f'])处理文件名,防止?f=../../etc/passwd路径穿越 - 下载链接变成
https://example.com/download-backup.php?f=20240512.sql,背后逻辑可加日志、限速、次数限制
配置再细,也挡不住路径放错或权限设宽;脚本再糙,只要备份不在 Web 树里,就少一个爆破面。这事的关键不是“怎么拦”,而是“别让它能被拦到”。











