如何在 Nginx.conf 中使用环境变量

如何在 Nginx.conf 中使用环境变量

我有一个运行 Nginx 的 docker 容器,它链接到另一个 docker 容器。第二个容器的主机名和 IP 地址在启动时作为环境变量加载到 Nginx 容器中,但在此之前并不知道(它是动态的)。我希望nginx.conf使用这些值 - 例如

upstream gunicorn {
    server $APP_HOST_NAME:$APP_HOST_PORT;
}

如何在启动时将环境变量放入 Nginx 配置中?

编辑1

这是整个文件,在下面建议的答案之后:

env APP_WEB_1_PORT_5000_TCP_ADDR;
# Nginx host configuration for django_app

# Django app is served by Gunicorn, running under port 5000 (via Foreman)
upstream gunicorn {
    server $ENV{"APP_WEB_1_PORT_5000_TCP_ADDR"}:5000;
}

server {
    listen 80;

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    location /static/ {
        alias /app/static/;
    }
    location /media/ {
        alias /app/media/;
    }
    location / {
        proxy_pass http://gunicorn;
    }
}

重新加载 nginx 然后出现错误:

$ nginx -s reload
nginx: [emerg] unknown directive "env" in /etc/nginx/sites-enabled/default:1

编辑2:更多细节

当前环境变量

root@87ede56e0b11:/# env | grep APP_WEB_1
APP_WEB_1_NAME=/furious_turing/app_web_1
APP_WEB_1_PORT=tcp://172.17.0.63:5000
APP_WEB_1_PORT_5000_TCP=tcp://172.17.0.63:5000
APP_WEB_1_PORT_5000_TCP_PROTO=tcp
APP_WEB_1_PORT_5000_TCP_PORT=5000
APP_WEB_1_PORT_5000_TCP_ADDR=172.17.0.63

根 nginx.conf:

root@87ede56e0b11:/# head /etc/nginx/nginx.conf
user www-data;
worker_processes 4;
pid /var/run/nginx.pid;
env APP_WEB_1_PORT_5000_TCP_ADDR;

站点nginx配置:

root@87ede56e0b11:/# head /etc/nginx/sites-available/default
# Django app is served by Gunicorn, running under port 5000 (via Foreman)
upstream gunicorn {
    server $ENV{"APP_WEB_1_PORT_5000_TCP_ADDR"}:5000;
}

server {
    listen 80;

重新加载 nginx 配置:

root@87ede56e0b11:/# nginx -s reload
nginx: [emerg] directive "server" is not terminated by ";" in /etc/nginx/sites-enabled/default:3

答案1

这里是另一个带有 envsubst 的例子。

nginxdocker image 已经运行过了envsubst/docker-entrypoint.d/20-envsubst-on-templates.sh你只需要在合适的位置放置一个模板文件:/etc/nginx/templates/my-file.conf.template

然后,您可以创建一个专用template文件,仅用于包含一个或多个map子句的变量,我们将使用这些子句作为自定义变量。您必须为该conf.d文件选择一个名称,以便它是 nginx 第一个采用的名称。

这是用 docker-compose 和三个文件解释的基本概念:

docker-compose.yml

version: "3.9"
services:
  nginx:
    image: nginx:1.23
    volumes:
        - ./template-variables:/etc/nginx/templates/10-variables.conf.template:ro

    environment:
        EXTERNAL_IP: "1.2.3.4"

模板变量

map $host $external_ip {
  default "$EXTERNAL_IP";
}

nginx.conf

server {
     location / {

          proxy_set_header X-Real-IP $external_ip;
      }
}

答案2

官方Nginx docker 文件:

在 nginx 配置中使用环境变量:

开箱即用,Nginx 不支持在大多数配置块中使用环境变量。

但是envsubst如果您需要在 nginx 启动之前动态生成 nginx 配置,则可以将其用作解决方法。

以下是使用 docker-compose.yml 的示例:

image: nginx
volumes:
 - ./mysite.template:/etc/nginx/conf.d/mysite.template
ports:
 - "8080:80"
environment:
 - NGINX_HOST=foobar.com
 - NGINX_PORT=80
command: /bin/bash -c "envsubst < /etc/nginx/conf.d/mysite.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'" 

mysite.template 文件可能包含如下变量引用:

listen ${NGINX_PORT};

更新:

但是您知道这会导致其 Nginx 变量如下:

proxy_set_header        X-Forwarded-Host $host;

损坏至:

proxy_set_header        X-Forwarded-Host ;

因此,为了防止这种情况,我使用了这个技巧:

我有一个运行 Nginx 的脚本,它在文件上用作docker-composeNginx 服务器的命令选项,我将其命名为run_nginx.sh

#!/usr/bin/env bash
export DOLLAR='$'
envsubst < nginx.conf.template > /etc/nginx/nginx.conf
nginx -g "daemon off;"

并且由于在脚本上定义了新的DOLLAR变量,现在我的Nginx 本身变量的文件内容如下:run_nginx.shnginx.conf.template

proxy_set_header        X-Forwarded-Host ${DOLLAR}host;

我定义的变量是这样的:

server_name  ${WEB_DOMAIN} www.${WEB_DOMAIN};

这里,这是我的真实用例。

答案3

官方 nginx 镜像建议使用envsubst, 但正如其他人指出的那样它将替换掉$host其他变量,这是不可取的。但幸运的envsubst是,将要替换的变量名称作为参数

为了避免向容器添加非常复杂的命令参数(如链接的示例所示),您可以编写一个 Docker 入口点脚本,该脚本将在执行命令之前填写环境变量。入口点脚本也是验证参数和设置默认值的好地方。

这是一个 nginx 容器的示例,它将API_HOST参数API_PORT作为环境变量。

nginx-default.conf.模板

resolver  127.0.0.11 valid=10s;  # recover from the backend's IP changing

server {
  listen  80;

  location / {
    root  /usr/share/nginx/html;
  }

  location /api {
    proxy_pass  http://${API_HOST}:${API_PORT};
    proxy_set_header  Host $http_host;
  }
}

docker-entrypoint.sh

#!/usr/bin/env sh
set -eu

envsubst '${API_HOST} ${API_PORT}' < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf

exec "$@"

Dockerfile

FROM nginx:1.15-alpine

COPY nginx-default.conf.template /etc/nginx/conf.d/default.conf.template

COPY docker-entrypoint.sh /
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["nginx", "-g", "daemon off;"]

答案4

使用 Lua 来实现这一点比听起来要简单得多:

server {
    set_by_lua $server_name 'return os.getenv("NGINX_SERVERNAME")';
}

我在这里发现了:

https://docs.apitools.com/blog/2014/07/02/using-environment-variables-in-nginx-conf.html

编辑:

显然这需要安装 lua 模块:https://github.com/openresty/lua-nginx-module

编辑2:

请注意,使用此方法您必须env在 Nginx 中定义变量:

env ENVIRONMENT_VARIABLE_NAME

您必须在 的顶层上下文中执行此操作,nginx.conf否则它将不起作用! 不能在 服务器块中或 的某些站点的配置中执行此操作/etc/nginx/sites-available,因为它包含在 上下文nginx.confhttp(不是顶层上下文)。

另请注意,如果您尝试使用此方法进行重定向,例如:

server {
    listen 80;
    server_name $server_name;
    return 301 https://$server_name$request_uri;
}

它也不会起作用:

2016/08/30 14:49:35 [emerg] 1#0: the duplicate "server_name" variable in /etc/nginx/sites-enabled/default:8

如果你给它一个单独的变量名:

set_by_lua $server_name_from_env 'return os.getenv("NGINX_SERVERNAME")';

server {
    listen 80;
    server_name $server_name_from_env;
    return 301 https://$server_name$request_uri;
}

nginx 不会解释它并会将您重定向到https://%24server_name_from_env/

相关内容