web-dev-qa-db-ja.com

Nginx.confで環境変数を使用する方法

[ https://stackoverflow.com/questions/21933955 からクロスポストおよび編集して、StackOverflowにはsysadminに似ていると考えられていました。]

別のドッカーコンテナーにリンクするNginxを実行するドッカーコンテナーがあります。 2番目のコンテナーのホスト名とIPアドレスは、起動時に環境変数としてNginxコンテナーに読み込まれますが、それまでは不明です(動的です)。 nginx.confこれらの値を使用するには-例.

upstream gunicorn {
    server $APP_Host_NAME:$APP_Host_PORT;
}

起動時に環境変数をNginx構成に取り込むにはどうすればよいですか?

EDIT 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
208

From 公式の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-composeファイルで使用される、Nginxを実行するスクリプトがあります。名前はrun_nginx.shです。

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

また、run_nginx.shスクリプトに新しいDOLLAR変数が定義されているため、Nginx自体の変数に対するnginx.conf.templateファイルの内容は次のようになります。

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

そして、私の定義した変数は次のようになります:

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

また、- ここ 、私の実際の使用例があります。

116
Omid Raha

ルアと一緒にやろう!

server {
    set_by_lua $curr_server_name 'return os.getenv("APP_Host_NAME")';
    set_by_lua $curr_server_port 'return os.getenv("APP_Host_PORT")';
    listen = $curr_server_port
    server_name = $curr_server_name;
}

(元の回答は廃止され、削除されました。これは更新された回答です。)

59
Ben Whaley

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:

このアプローチでは、Nginxでenv変数を定義する必要があることに注意してください。

env ENVIRONMENT_VARIABLE_NAME

nginx.confのトップレベルのコンテキストでこれを行う必要があります。そうしないと機能しません。 httpコンテキスト(最上位のコンテキストではない)の/etc/nginx/sites-availableに含まれているため、サーバーブロックまたはnginx.confの一部のサイトの構成にはありません。

また、このアプローチでは、リダイレクトを行おうとすると、次のようになります。

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/にリダイレクトします。

36

公式のnginxイメージ envsubst を使用することをお勧めしますが、 他の人が指摘したように は、$Hostやその他の変数も置き換えるため、望ましくありません。 。しかし、幸いにもenvsubstパラメータとして置き換える変数の名前を取得 できます。

(リンクされた例のように)コンテナーに対する非常に複雑なコマンドパラメーターを回避するために、コマンドを実行する前に環境変数を入力するDockerエントリーポイントスクリプトを記述できます。エントリポイントスクリプトは、パラメータの検証とデフォルト値の設定にも適しています。

以下は、API_HostおよびAPI_PORTパラメータを環境変数として受け取るnginxコンテナの例です。

nginx-default.conf.template

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;"]
26
Esko Luontola

役に立つかもしれないし、役に立たないかもしれないものを書きました: https://github.com/yawn/envplate

環境変数への$ {key}参照を使用して構成ファイルをインライン編集します。オプションで、バックアップを作成し、その内容を記録します。 Goで書かれており、結果の静的バイナリはLinuxおよびMacOSのリリースタブから簡単にダウンロードできます。

また、プロセスのexec()、デフォルトの置き換え、ログ記録を行うことができ、適切な障害セマンティクスを持っています。

14
yawn

Erbの使用に関する回答を参照すると、次のように行うことができます。

NGINX構成ファイルを環境変数を含むerbファイルとして書き込み、erbコマンドを使用して通常の構成ファイルに対して評価します。

erb nginx.conf.erb > nginx.conf

Nginx.conf.erbファイルのサーバーブロック内に

listen <%= ENV["PORT"] %>;
5
Ruifeng Ma

私がしたことは erb

cat nginx.conf  | grep -i error_log

error_log <%= ENV["APP_ROOT"] %>/nginx/logs/error.log;

--erbを使用した後

export APP_ROOT=/tmp

erb nginx.conf  | grep -i error_log

error_log /tmp/nginx/logs/error.log;

これは Cloudfoundry staticfile-buildpack で使用されます

Nginx設定の例: https://github.com/cloudfoundry/staticfile-buildpack/blob/master/conf/nginx.conf

あなたの場合

head /etc/nginx/nginx.conf
user www-data;
worker_processes 4;
pid /var/run/nginx.pid;
env APP_WEB_1_PORT_5000_TCP_ADDR;
upstream gunicorn {
    server $APP_Host_NAME:$APP_Host_PORT;
}

なる

head /etc/nginx/nginx.conf
user www-data;
worker_processes 4;
pid /var/run/nginx.pid;
env <%= ENV["APP_WEB_1_PORT_5000_TCP_ADDR"] %>
upstream gunicorn {
    server <%= ENV["APP_Host_NAME"] %>:<%= ENV["APP_Host_PORT"] %>
}

#After applying erb

export APP_WEB_1_PORT_5000_TCP_ADDR=12.12.12.12
export APP_Host_NAME=test
export APP_Host_PORT=7089 

erb /etc/nginx/nginx.conf

head /etc/nginx/nginx.conf
user www-data;
worker_processes 4;
pid /var/run/nginx.pid;
env 12.12.12.12
upstream gunicorn {
    server test: 7089
}
5
Sabith K S

シェルスクリプトを使用してこれを実現します。

Nginxテンプレートは次のとおりです。

server {

    listen 80;
    server_name ___MY_DOMAIN_NAME___;
    charset utf-8;

    location /proxy {
        proxy_pass http://___PROXY_IP___:___PROXY_PORT___;
        proxy_set_header Host            $Host;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-Proto https;
    }

    location / {
        return         200;
    }

}

そして、環境変数を置き換えるスクリプトは次のとおりです。

echo sleep 3
sleep 3

echo build starting nginx config


echo replacing ___MY_DOMAIN_NAME___/$MY_DOMAIN_NAME
echo replacing ___PROXY_IP___/$LETSENCRYPT_IP
echo replacing ___PROXY_PORT___/$PROXY_PORT

sed -i "s/___MY_DOMAIN_NAME___/$MY_DOMAIN_NAME/g" /etc/nginx/nginx.conf
sed -i "s/___PROXY_IP___/$PROXY_IP/g" /etc/nginx/nginx.conf
sed -i "s/___PROXY_PORT___/$PROXY_PORT/g" /etc/nginx/nginx.conf

cat /etc/nginx/nginx.conf

if [ -z "$MY_DOMAIN_NAME" ]; then
    echo "Need to set MY_DOMAIN_NAME"
    exit 1
fi  
if [ -z "$LETSENCRYPT_IP" ]; then
    echo "Need to set LETSENCRYPT_IP"
    exit 1
fi  
if [ -z "$LETSENCRYPT_PORT" ]; then
    echo "Need to set LETSENCRYPT_PORT"
    exit 1
fi
if [ -z "$LETSENCRYPT_HTTPS_IP" ]; then
    echo "Need to set LETSENCRYPT_HTTPS_IP"
    exit 1
fi 
if [ -z "$LETSENCRYPT_HTTPS_PORT" ]; then
    echo "Need to set LETSENCRYPT_HTTPS_PORT"
    exit 1
fi

nginx -g 'daemon off;'
3
Geige V

私はこれが古い質問であることを知っていますが、誰かがこれに遭遇した場合(私が今持っているように)に備えて、これを行うはるかに良い方法があります。 dockerはリンクされたコンテナのエイリアスを/ etc/hostsに挿入するため、次のようにできます

upstream upstream_name {
    server docker_link_alias;
}

dockerコマンドがdocker run --link othercontainer:docker_link_alias nginx_container

3
cderwin

別のオプション...今日、このツールを見つけました: https://github.com/kreuzwerker/envplate ... Goで記述されているため、簡単にインストールできます。使い方はとても簡単です。ただし、テンプレート変数をnginx.confに配置する必要があります。

例えば ​​${SOME_ENV_VAR}は、ファイルでenvplateのepコマンドが呼び出されると置き換えられます。したがって、Dockerfileがそのバイナリの取得に失敗したり、何らかの理由でDockerfileが実行されなかったりすると、構成が無効になります。 Perlやlua拡張の使用など、他のソリューションと比較した場合のちょっとした注意。

環境変数が設定されていない場合にも、デフォルト値を設定する方法がとても気に入っています。例${SOME_ENV_VAR:default-value}(値をエスケープできます)。この場合も、envplateは引き続き正常に実行される必要があります。

このようなアプローチを使用する利点の1つは、他の方法では必要のないあらゆる種類の追加モジュールをインストールするため、必要以上に大きなDockerイメージが作成されないことです。物事が複雑になり始め、デフォルト値の機能が含まれている場合は、sedを使用するよりも簡単かもしれません。

2
Tom

多くの方法があります。一部はいくつかの回答で概説されています。

ngx_http_js_moduleを使用する場合、JSでそれを行う方法もあります。

## /etc/nginx/fetch_env.js
function fetch_upstream_Host(r) {
  return process.env.UPSTREAM_Host;
}

function fetch_upstream_port(r) {
  return process.env.UPSTREAM_PORT;
}

そして

## /etc/nginx/nginx.conf
load_module modules/ngx_http_js_module.so;

env UPSTREAM_Host;
env UPSTREAM_PORT;

http {
  js_include fetch_env.js;
  js_set $upstream_Host fetch_upstream_Host;
  js_set $upstream_port fetch_upstream_port;

  server {
    ...

    location / {
      ...

      proxy_pass http://$upstream_Host:$upstream_port;
    }
  }

Njsモジュール0.33以降を使用していることを確認してください

2
Trung Lê

sedアプローチの使用例を以下に示します。必ずしも優れているとは限りませんが、一部のユーザーには役立つ場合があります。まず、置換するカスタムキーワードをconfファイル内に追加します。次に、ENV変数を宣言するdockerfileを作成し、次にCMDを使用してsedを使用して構成を編集し、nginxを明示的に実行します。

したがって、default.confにキーワードdocker_Hostが含まれているとします。

location /api { proxy_pass http://docker_Host:9000/api; }

そして、次のようなDockerfileを記述します。

ENV docker_Host localhost
ADD default.conf /etc/nginx/conf.d/default.conf
CMD sed -i.bak s/docker_Host/$docker_Host/g /etc/nginx/conf.d/default.conf &&   nginx -g "daemon off;"

次に、イメージをビルドし、コンテナを実行します

docker run -d -p 80:80 -e "docker_Host=${env:COMPUTERNAME}" imagename
1
Steven

もう1つの可能性は、正規表現で「sed」コマンドを使用することです。そうすれば、構成ファイルをいじる必要がまったくなくなります。これにより、設定ファイルを通常どおり使用できますが、Dockerを実行すると、値がenv変数と入れ替えられます。これはどれも「検索して置き換える構成ファイルにテキスト文字列を追加する」ことはありません。

環境変数を使用して、置換値を含むrun.shファイルを作成できます。

この行の「7」を変更するには:

client_body_timeout 7s;         #Default 60s

client_body_timeoutを検索行として使用し、$ client_body_timeoutを置換環境変数として使用するSedコマンド:

sed -i "s/\(client_body_timeout\).*\?\;/\1 $client_body_timeout;/" /usr/local/nginx/conf/nginx.conf

設定するすべてのパラメーターに対してこの行をコピーして貼り付け、configオプションでclient_body_timeoutを変更し、関連付けられているenv変数で$ client_body_timeoutを変更します。既存の設定ファイルを使用してください。それでうまくいきます。

1
Jeff

上記の答えは古くなっているので、luaでこれを行う適切な方法:

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

0
Eric Meadows