nginx主配置文件不支持直接解析环境变量,需通过启动前注入实现:常用envsubst模板替换;或用include+脚本动态生成子配置;或用map/geo模块实现请求级动态行为;set指令无法读取系统环境变量。

Nginx 主配置文件(nginx.conf)本身不支持直接解析环境变量(比如写 access_log $LOG_PATH/access.log; 是无效的),但可以通过“启动前注入”方式,让环境变量参与配置生成。核心思路是:不靠 Nginx 运行时读取,而靠外部工具在启动前把变量替换成真实值。
用 envsubst 模板替换生成最终配置
这是最常用、最轻量、无需修改 Nginx 源码的方式。适用于 Docker 或容器化部署场景。
-
准备一个带占位符的模板文件(如
/etc/nginx/nginx.conf.tpl):user $NGINX_USER; pid /run/nginx.pid; events { worker_connections $WORKER_CONNECTIONS; } http { access_log /var/log/nginx/$LOG_NAME.access.log; error_log /var/log/nginx/$LOG_NAME.error.log; server { listen $LISTEN_PORT; server_name $SERVER_NAME; location / { proxy_pass http://$BACKEND_HOST:$BACKEND_PORT; } } } -
启动时执行替换(常见于 Docker
entrypoint.sh或command):envsubst /etc/nginx/nginx.conf && exec nginx -g "daemon off;"
-
运行容器时传入环境变量:
docker run -d \ --name my-nginx \ -e NGINX_USER=www-data \ -e WORKER_CONNECTIONS=2048 \ -e LOG_NAME=prod \ -e LISTEN_PORT=8080 \ -e SERVER_NAME=api.example.com \ -e BACKEND_HOST=10.0.2.5 \ -e BACKEND_PORT=3000 \ -v $(pwd)/nginx.conf.tpl:/etc/nginx/nginx.conf.tpl \ nginx:alpine
✅ 优点:简单可靠,所有变量一次性注入,兼容任意 Nginx 版本
⚠️ 注意:envsubst默认替换所有$VAR和${VAR}形式;若配置中含字面量$(如正则\$),需转义为\$或用envsubst '$VAR'显式指定变量列表
用 include + 外部脚本动态生成子配置
适合需要部分参数高频变更(如上游节点、路由规则),又不想每次 reload 全局配置的场景。
-
在主配置中
include可变片段:http { include /etc/nginx/conf.d/upstreams.conf; # 动态 upstream include /etc/nginx/conf.d/routes.conf; # 动态 location 路由 ... } -
编写脚本(如
gen-upstream.sh),读取环境变量或配置中心数据,生成upstreams.conf:echo "upstream backend {" > /etc/nginx/conf.d/upstreams.conf for host in $UPSTREAM_LIST; do echo " server $host weight=1;" >> /etc/nginx/conf.d/upstreams.conf done echo "}" >> /etc/nginx/conf.d/upstreams.conf 启动前运行该脚本,再
nginx -t && nginx -s reload
✅ 优点:可组合外部数据源(Consul、etcd、K8s ConfigMap),支持灰度/AB 测试逻辑
⚠️ 注意:include文件内容必须语法合法;建议配合nginx -t验证后再 reload
利用 map 或 geo 实现请求级动态行为(无需 reload)
这类模块在每次请求时实时计算,适合根据请求特征切换后端、日志路径或限速策略——变量值本身可来自环境,但逻辑需提前写死在 map 块中。
-
示例:按
Host头选择不同日志文件名(需提前定义映射关系):map $host $log_file { default "default"; ~^app\. "app"; ~^api\. "api"; } http { access_log /var/log/nginx/$log_file.access.log; ... }此处
$log_file是 map 计算结果,不是环境变量,但你可以用环境变量控制 map 内容(需 reload);真正“免 reload”的动态性体现在请求时匹配,而非配置加载阶段。
✅ 优点:零延迟生效,适合 A/B、灰度、地域分流等场景
⚠️ 注意:map块本身修改仍需nginx -s reload,只是其内部逻辑对每个请求实时生效
不推荐的方式:尝试用 set + 环境变量间接引用
Nginx 的 set 指令只能定义字符串变量,不能从系统环境读取($ENV_VAR 不存在)。以下写法无效:
set $backend_host $BACKEND_HOST; # ❌ Nginx 不识别 $BACKEND_HOST proxy_pass http://$backend_host;
除非你用 OpenResty(支持 os.getenv()),否则原生 Nginx 不提供该能力。
不复杂但容易忽略











