it-swarm.com.de

Wie kann ich Umgebungsvariablen in Nginx.conf verwenden?

[Cross-posted und bearbeitet von https://stackoverflow.com/questions/21933955 , da es für StackOverflow als zu sysadminartig angesehen wurde.]

Ich habe einen Docker-Container, auf dem Nginx ausgeführt wird und der mit einem anderen Docker-Container verknüpft ist. Der Hostname und die IP-Adresse des zweiten Containers werden beim Start als Umgebungsvariablen in den Nginx-Container geladen, sind jedoch vorher nicht bekannt (dynamisch). Ich will mein nginx.conf, um diese Werte zu verwenden - z.

upstream gunicorn {
    server $APP_Host_NAME:$APP_Host_PORT;
}

Wie kann ich beim Start Umgebungsvariablen in die Nginx-Konfiguration übernehmen?

EDIT 1

Dies ist die gesamte Datei nach der unten vorgeschlagenen Antwort:

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 neu laden dann Fehler:

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

EDIT 2: weitere Details

Aktuelle Umgebungsvariablen

[email protected]:/# 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

Root nginx.conf:

[email protected]:/# head /etc/nginx/nginx.conf
user www-data;
worker_processes 4;
pid /var/run/nginx.pid;
env APP_WEB_1_PORT_5000_TCP_ADDR;

Site Nginx Konfiguration:

[email protected]:/# 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-Konfiguration neu laden:

[email protected]:/# nginx -s reload
nginx: [emerg] directive "server" is not terminated by ";" in /etc/nginx/sites-enabled/default:3
208

From die offizielle Nginx-Docker-Datei:

Verwenden von Umgebungsvariablen in der Nginx-Konfiguration:

Standardmäßig unterstützt Nginx die Verwendung von Umgebungsvariablen in den meisten Konfigurationsblöcken nicht.

envsubst kann jedoch als Problemumgehung verwendet werden, wenn Sie Ihre Nginx-Konfiguration dynamisch generieren müssen, bevor Nginx gestartet wird.

Hier ist ein Beispiel mit 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;'" 

Die Datei mysite.template kann dann folgende Variablenreferenzen enthalten:

listen ${NGINX_PORT};

Update:

Aber Sie wissen, dass dies auf seine Nginx-Variablen zurückzuführen ist:

proxy_set_header        X-Forwarded-Host $Host;

beschädigt an:

proxy_set_header        X-Forwarded-Host ;

Um dies zu verhindern, verwende ich diesen Trick:

Ich habe ein Skript zum Ausführen von Nginx, das auf dem docker-compose Datei als Befehlsoption für Nginx Server, ich nannte es run_nginx.sh:

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

Und wegen der definierten neuen DOLLAR Variablen auf run_nginx.sh Skript, jetzt Inhalt meines nginx.conf.template Datei für Nginx selbst Variable ist wie folgt:

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

Und für meine definierte Variable ist das so:

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

Auch hier , dafür gibt es meinen wirklichen Anwendungsfall.

116
Omid Raha

Mach es mit Lua!

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;
}

(Die ursprüngliche Antwort ist veraltet und wurde entfernt. Dies ist eine aktualisierte Antwort.)

59
Ben Whaley

Dies mit Lua zu tun ist wesentlich einfacher als es sich anhört:

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

Das habe ich hier gefunden:

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

Bearbeiten:

Anscheinend erfordert dies die Installation des Lua-Moduls: https://github.com/openresty/lua-nginx-module

Bearbeiten 2:

Beachten Sie, dass Sie bei diesem Ansatz die Variable env in Nginx definieren müssen:

env ENVIRONMENT_VARIABLE_NAME

Sie müssen dies im Toplevel-Kontext in nginx.conf Tun, sonst funktioniert es nicht! Nicht im Serverblock oder in der Konfiguration einer Site in /etc/nginx/sites-available, Da nginx.conf In http Kontext (der kein Kontext der obersten Ebene ist) enthalten ist.

Beachten Sie auch, dass bei diesem Ansatz, wenn Sie versuchen, eine Umleitung durchzuführen, z.

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

es wird nicht so gut funktionieren:

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

Und wenn Sie ihm einen separaten Variablennamen geben:

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 interpretiert es nicht und leitet Sie zu https://%24server_name_from_env/ weiter.

36

Das offizielle Nginx-Bild empfiehlt die Verwendung von envsubst , aber wie von anderen hervorgehoben ersetzt auch $Host und andere Variablen, was nicht wünschenswert ist. Aber zum Glück kann envsubstals Parameter die Namen der zu ersetzenden Variablen verwenden .

Um einen sehr komplexen Befehlsparameter für den Container zu vermeiden (wie im verknüpften Beispiel), können Sie ein Docker-Einstiegspunktskript schreiben, das die Umgebungsvariablen ausfüllt, bevor Sie den Befehl ausführen. Das Einstiegspunktskript ist auch ein guter Ort, um die Parameter zu überprüfen und Standardwerte festzulegen.

Hier ist ein Beispiel eines Nginx-Containers, der API_Host und API_PORT Parameter als Umgebungsvariablen.

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 "[email protected]"

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

Ich habe etwas geschrieben, das hilfreich sein kann oder nicht: https://github.com/yawn/envplate

Es bearbeitet Inline-Konfigurationsdateien mit $ {key} -Verweisen auf Umgebungsvariablen und erstellt optional Sicherungen/protokolliert, was es tut. Es ist in Go geschrieben und die resultierende statische Binärdatei kann einfach von der Registerkarte "Release" für Linux und MacOS heruntergeladen werden.

Es kann auch Prozesse ausführen (), Standardeinstellungen ersetzen, protokollieren und verfügt über eine sinnvolle Fehlersemantik.

14
yawn

In Bezug auf die Antwort zur Verwendung von erb kann dies wie folgt erfolgen.

Schreiben Sie die NGINX-Konfigurationsdatei als erb-Datei, die die Umgebungsvariable enthält, und werten Sie sie mit dem Befehl erb in eine normale Konfigurationsdatei aus.

erb nginx.conf.erb > nginx.conf

Innerhalb des Serverblocks der Datei nginx.conf.erb könnte es sein

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

Was ich getan habe war, das erb zu verwenden!

cat nginx.conf  | grep -i error_log

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

--Nach Verwendung von erb

export APP_ROOT=/tmp

erb nginx.conf  | grep -i error_log

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

Dies wird im Cloudfoundry staticfile-buildpack verwendet

Beispiel für eine Nginx-Konfiguration: https://github.com/cloudfoundry/staticfile-buildpack/blob/master/conf/nginx.conf

In Ihrem Fall

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;
}

werden

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

Ich erreiche dies mit einem Shell-Skript.

Hier ist die Nginx-Vorlage:

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;
    }

}

Und das Skript zum Ersetzen der Umgebungsvariablen ist hier:

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

Ich weiß, dass dies eine alte Frage ist, aber nur für den Fall, dass jemand darauf stößt (wie ich es jetzt getan habe), gibt es einen viel besseren Weg, dies zu tun. Da Docker den Alias ​​des verknüpften Containers in/etc/hosts einfügt, können Sie dies einfach tun

upstream upstream_name {
    server docker_link_alias;
}

angenommen, Ihr Docker-Befehl ist so etwas wie docker run --link othercontainer:docker_link_alias nginx_container.

3
cderwin

Eine andere Option ... Ich habe dieses Tool heute gerade gefunden: https://github.com/kreuzwerker/envplate ... In Go geschrieben, kann es sehr einfach installiert werden. Die Verwendung ist recht einfach. Sie müssen jedoch Vorlagenvariablen in Ihrer nginx.conf platzieren.

Beispielsweise ${SOME_ENV_VAR} wird ersetzt, wenn der Befehl ep von envplate für die Datei aufgerufen wird. Sollte Ihre Docker-Datei diese Binärdatei nicht erhalten oder aus irgendeinem Grund nicht ausgeführt werden, würde Ihre Konfiguration ungültig. Nur eine kleine Anmerkung im Vergleich zu anderen Lösungen wie der Verwendung von Perl- oder Lua-Erweiterungen.

Mir gefällt sehr, wie Sie auch Standardwerte festlegen können, wenn die Umgebungsvariable nicht festgelegt ist. Ex. ${SOME_ENV_VAR:default-value} (und Sie können Werte umgehen). Auch hier muss envplate noch erfolgreich ausgeführt werden.

Ein Vorteil eines solchen Ansatzes besteht darin, dass Sie kein Docker-Image erhalten, das größer als erforderlich ist, da Sie alle Arten von zusätzlichen Modulen installiert haben, die Sie sonst nicht benötigen. Es kann auch einfacher sein als sed zu verwenden, wenn die Dinge komplex werden und es diese Standardwertfunktionalität enthält.

2
Tom

Es gibt viele Wege. Einige wurden in einigen Antworten umrissen.

Wenn Sie das ngx_http_js_module gibt es auch eine Möglichkeit, dies mit JS zu tun:

## /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;
}

und

## /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;
    }
  }

Bitte stellen Sie sicher, dass Sie das njs-Modul 0.33 oder neuer verwenden

2
Trung Lê

Hier ist ein Beispiel für die Verwendung des Ansatzes sed, der nicht unbedingt besser ist, aber für einige nützlich sein kann. Fügen Sie zunächst ein benutzerdefiniertes Schlüsselwort hinzu, das in der conf-Datei ersetzt werden soll. Zweitens erstellen Sie eine Docker-Datei, die eine ENV -Variable deklariert, und dann eine CMD, die sed verwendet, um die Konfiguration zu bearbeiten, bevor nginx explizit ausgeführt wird.

Angenommen, Ihre default.conf enthält diese mit dem Schlüsselwort docker_Host:

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

Und schreiben Sie Ihre Docker-Datei ähnlich wie:

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;"

Erstellen Sie dann das Image und führen Sie den Container mit aus

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

Eine andere Möglichkeit besteht darin, den Befehl 'sed' mit regulären Ausdrücken zu verwenden, damit Sie sich überhaupt nicht mit Ihren Konfigurationsdateien herumschlagen müssen! Auf diese Weise können Sie Ihre Konfigurationsdateien normal verwenden. Wenn Sie jedoch Docker ausführen, werden die Werte gegen die env-Variablen ausgetauscht. Nichts davon "Fügen Sie Ihren Konfigurationsdateien, durch die Sie suchen und die Sie ersetzen, eine Textzeichenfolge hinzu."

Sie können mit Ihren Umgebungsvariablen eine run.sh-Datei mit Ersatzwerten erstellen.

So ändern Sie die "7s" in dieser Zeile:

client_body_timeout 7s;         #Default 60s

Sed-Befehl mit client_body_timeout als Suchzeile und $ client_body_timeout als Ersatz-Umgebungsvariable:

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

Kopieren Sie diese Zeile für jeden Parameter, den Sie festlegen möchten, und fügen Sie sie ein. Ändern Sie das client_body_timeout mit der Konfigurationsoption und $ client_body_timeout mit der ihm zugeordneten env-Variablen. Verwenden Sie mit vorhandenen Konfigurationsdatei und es wird einfach funktionieren.

1
Jeff

Der richtige Weg, dies mit lua zu tun, da die obige Antwort veraltet ist:

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

0
Eric Meadows