Nginx 在 Linux 下不支持运行时直接读取系统环境变量,需通过 envsubst 预渲染模板或 map/set 实现动态配置:前者用于构建期变量替换,后者用于运行期请求级映射;map 定义在 http 块顶层,set 作用域受限且不可跨块。

Linux 下 Nginx 本身不支持运行时环境变量注入(比如 $HOST 直接从 shell 环境读取),但可通过两种正交路径实现“动态变量处理”:一种是配置期用 envsubst 预渲染模板(适合 Docker 或 CI/CD 场景);另一种是运行期用 map + set 做请求级动态映射(适合路由分流、灰度等)。硬要让 Nginx 启动时读系统环境变量,它做不到——那是容器或启动脚本该干的事。
用 envsubst 在启动前替换模板变量
这是最常用、最可控的动态配置方式,尤其在 Docker 中由官方镜像原生支持。本质是把 Nginx 配置写成模板,启动时用当前环境变量填充生成真实配置文件。
-
envsubst只认${VAR}或$VAR形式,不支持${VAR:-default}这类 bash 默认值语法;如需 fallback,得靠外部脚本预设变量值 - 模板文件必须放在
NGINX_ENVSUBST_TEMPLATE_DIR(默认/etc/nginx/templates),且后缀匹配NGINX_ENVSUBST_TEMPLATE_SUFFIX(默认.template) - 如果只希望替换部分变量(避免污染),传入变量名列表更安全:
envsubst '$NGINX_PORT $BACKEND_URL' < default.conf.template > default.conf - 注意权限:模板文件和输出目录需对 nginx worker 用户可读写,否则 entrypoint 脚本会失败,报错类似
envsubst: can't open /etc/nginx/conf.d/default.conf: Permission denied
用 map 实现运行时条件变量映射
map 是唯一能跨 server 和 location 复用的“全局变量”机制,惰性求值、无性能损耗,适合根据请求特征做决策。
-
map必须定义在http块顶层,不能嵌套在server或location内,否则 reload 时报"map" directive is not allowed here - 源变量必须存在,比如
$arg_env(查询参数)、$cookie_user_role(Cookie)、$http_x_forwarded_for(Header),不能写未声明的$my_custom_var - 正则匹配需加
~(大小写敏感)或~*(忽略大小写),且default分支不可省略,否则未匹配时变量为空字符串,可能引发proxy_pass解析失败 - 示例:按请求头切换后端
map $http_x_env $upstream_backend {
default "backend-prod";
"staging" "backend-staging";
"dev" "backend-dev";
}
之后在任意 location 中直接用 proxy_pass http://$upstream_backend; 即可。
set 变量的坑:作用域窄、顺序敏感、不能跨块
set 看似灵活,实则极易误用。它不是赋值语句,而是“当前请求上下文内的一次性绑定”,且受块级作用域严格限制。
-
set不允许出现在http块顶层(即不在任何server内),否则报"set" directive is not allowed here -
server里set $flag "on";,location /api里无法直接读取 —— 它不是继承关系,而是独立作用域;除非你把location写在该server块内且没被其他同名set覆盖,否则就是未定义 - 多个
set赋同名变量,以配置文件中**最后出现的为准**,前面的会被静默覆盖,调试时容易漏看 - 拼接变量务必用花括号防歧义:
"${host}_api"正确,"$host_api"会被解析为变量$host_api(不存在 → 空字符串)
宝塔面板下安全加 map 全局变量
宝塔默认禁止直接改 nginx.conf,硬改会被升级覆盖。正确做法是用 include 引入独立文件,既隔离风险又方便版本管理。
- 在
/www/server/nginx/conf/下新建global_vars.map,内容只含map块,不要包http { }或其他指令 - 在网站配置的
server { }块顶部(listen指令之前)加一行:include /www/server/nginx/conf/global_vars.map; - 确认该 include 路径在
nginx -t时能被正确加载,否则 reload 失败;常见错误是路径拼错或文件权限不对(需 nginx 用户可读)
真正难的不是写对语法,而是想清楚变量生命周期:envsubst 是构建时静态展开,map 是运行时按需查表,set 是请求内临时绑定。混用这三者而不厘清边界,配置会越来越不可维护。


















