nginx 不支持 root 指令直接使用变量,但可通过 map 提前映射域名到绝对路径、rewrite + alias 重写 uri、或 lua 运行时设置 document_root 实现多租户目录隔离,需严格防范路径穿越与权限风险。

Nginx 本身不支持直接在 root 指令中使用变量(如 $host、$subdomain)来动态指定根目录,因为 root 在配置解析阶段求值,而变量在请求处理阶段才可用。但通过合理组合 server_name、map、root 和 alias(或 try_files),可以安全、高效地实现多租户目录隔离。
用 map 提前映射租户到路径
这是最推荐的方式:用 map 指令在全局(http 块)中将域名或子域名映射为文件系统路径,再在 server 块中引用该变量作为 root。
- 在
http{}块中定义映射关系,避免重复判断和正则开销 - 路径必须是绝对路径,且确保 Nginx 工作进程有读取权限
- 可配合正则匹配泛域名(如
~^(?<sub>.+)\.example\.com$</sub>)提取租户名
示例:
http {
map $host $tenant_root {
default /var/www/default;
~^(?<sub>.+)\.example\.com$ /var/www/tenants/$sub;
tenant-a.example.com /var/www/tenants/tenant-a;
tenant-b.example.com /var/www/tenants/tenant-b;
}
server {
listen 80;
server_name ~^(.+)\.example\.com$ example.com;
root $tenant_root;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
}</sub>
用 rewrite + alias 实现路径重写(仅限特定 location)
当租户资源需统一入口(如所有请求都走 /app/),可用 rewrite 提取租户并重写 URI,再用 alias 指向对应目录。注意:alias 不同于 root,它会替换整个 location 路径段。
- 适用于租户静态资源放在统一子路径下(如
/var/www/tenants/{name}/public/) - 必须配合
location使用,不能用于整个 server 块的 root 替代 - 重写后 URI 需与 alias 目录结构对齐,否则 404
示例:
server {
listen 80;
server_name ~^(?<tenant>.+)\.example\.com$;
location / {
rewrite ^/(.*)$ /$tenant/$1 break;
alias /var/www/tenants/;
try_files $uri $uri/ =404;
}
}</tenant>
⚠️ 注意:alias 后路径末尾是否带 / 影响拼接逻辑,务必测试验证。
用 Lua 或 OpenResty 做运行时 root 切换(高级场景)
若需更灵活的租户路由逻辑(如查数据库、校验租户状态、灰度分流),可借助 ngx_lua 模块在 access_by_lua_block 中设置 ngx.var.document_root,再配合 root $document_root。
- 需编译安装 OpenResty 或启用 lua-nginx-module
- 性能略低于纯静态 map,但扩展性强
- 务必加缓存(如 shared dict)避免每次请求查库
示例片段:
location / {
access_by_lua_block {
local tenant = ngx.var.host:match("^(%w+)%.")
if tenant then
local path = "/var/www/tenants/" .. tenant
if file_exists(path) then
ngx.var.document_root = path
else
ngx.exit(404)
end
end
}
root $document_root;
try_files $uri $uri/ =404;
}
安全与运维关键点
动态 root 易引入路径穿越、越权访问等风险,必须严格约束:
- 所有租户目录应位于同一父目录下(如
/var/www/tenants/),禁止使用../或绝对路径跳转 - 租户名需白名单过滤(只允许字母数字、短横线),避免注入非法路径
- 每个租户目录的 owner 应为独立系统用户,Nginx worker 进程以最小权限运行(如
www-data) - 配合
open_file_cache提升静态文件性能,但注意 cache key 包含变量时需谨慎
不复杂但容易忽略。











