Nginx的root指令不支持运行时变量,但可通过map预解析租户标识为绝对路径变量(如$tenant_root),再在location中引用该变量实现安全高效的多租户静态资源动态映射,无需if、rewrite,符合官方推荐。

用 map 提前解析租户标识并映射到绝对路径
在 http 块中定义 map,将请求特征(如子域名、请求头或 URI 参数)映射为合法文件系统路径:
- 按子域名识别租户(最常见):
map $host $tenant_root {<br> ~^(?<t>[^.]+)\.example\.com$ /var/www/tenants/$t/;<br> default /var/www/tenants/default/;<br> }
该规则提取abc.example.com中的abc,映射为/var/www/tenants/abc/ - 按请求头识别(适合 API 网关场景):
map $http_x_tenant_id $tenant_root {<br> "acme" /var/www/tenants/acme/;<br> "beta" /var/www/tenants/beta/;<br> default /var/www/tenants/shared/;<br> } - 所有分支必须覆盖,未匹配时变量为空 → 导致 404,所以 default 是强要求
在 location 中显式使用 $tenant_root 作为 root 值
server 块内不再设全局 root,而是按需在每个 location 中引用变量:
- 根路径服务租户主页:
location / {<br> root $tenant_root;<br> try_files $uri $uri/index.html =404;<br> }
请求abc.example.com/→ 查找/var/www/tenants/abc/index.html - 静态资源子路径(如 /assets/)建议用 alias 避免拼接错误:
location ^~ /assets/ {<br> alias $tenant_root/assets/;<br> }
请求/assets/logo.png→ 直接定位到/var/www/tenants/abc/assets/logo.png,不会多出一层/assets/ - 不推荐对带前缀路径用 root,例如
location /assets/ { root $tenant_root; }会导致实际路径变成$tenant_root/assets/assets/logo.png
租户隔离与权限控制要点
变量映射只是第一步,生产环境还需保障安全与健壮性:
- 所有
$tenant_root值必须是**绝对路径**,且以/开头;相对路径或空值会引发 404 或目录遍历风险 - Nginx worker 进程需对各租户目录有读取权限(建议统一属组 + 只读权限,禁用执行位)
- 配合
limit_rate或auth_request可做租户级限流或鉴权前置 - 若租户目录由自动化流程创建(如 CI/CD),建议用符号链接指向
latest,实现零停机更新
为什么不直接用 if + set + root?
看似更直观,但存在明显缺陷:
-
if在 location 中性能差、逻辑易错,Nginx 官方明确不推荐用于路径重写 -
set定义的变量在某些上下文(如日志、root)中不可见,行为不可靠 -
map是编译期预处理、线程安全、零开销,天然适配多租户高并发场景

















