388 votes

Comment puis-je utiliser des variables d'environnement dans Nginx.conf ?

J'ai un conteneur docker exécutant Nginx, qui est lié à un autre conteneur docker. Le nom d'hôte et l'adresse IP du deuxième conteneur sont chargés dans le conteneur Nginx en tant que variables d'environnement au démarrage, mais ne sont pas connus avant (elles sont dynamiques). Je veux que mon nginx.conf utilise ces valeurs - par exemple

upstream gunicorn {
    server $APP_HOST_NAME:$APP_HOST_PORT;
}

Comment puis-je obtenir des variables d'environnement dans la configuration de Nginx au démarrage?

EDIT 1

Voici l'intégralité du fichier, après la réponse suggérée ci-dessous :

env APP_WEB_1_PORT_5000_TCP_ADDR;
# Configuration hôte Nginx pour l'application django_app 

# L'application Django est servie par Gunicorn, fonctionnant sous le 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;
    }
}

Le rechargement de nginx produit une erreur :

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

EDIT 2: plus de détails

Variables d'environnement actuelles

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 racine :

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;

Configuration du site nginx :

root@87ede56e0b11:/# head /etc/nginx/sites-available/default
# L'application Django est servie par Gunicorn, fonctionnant sous le port 5000 (via Foreman)
upstream gunicorn {
    server $ENV{"APP_WEB_1_PORT_5000_TCP_ADDR"}:5000;
}

server {
    listen 80;

Recharger la configuration nginx :

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

11 votes

Ce n'est pas une solution générique pour les variables d'environnement, mais si vous souhaitez utiliser des variables d'environnement pour les noms d'hôtes / adresses IP des serveurs en amont, notez que Docker (du moins dans les versions récentes) modifie /etc/hosts pour vous. Voir docs.docker.com/userguide/dockerlinks Cela signifie que si votre conteneur lié s'appelle 'app_web_1', Docker créera une ligne dans /etc/hosts de votre conteneur Nginx. Vous pouvez donc simplement remplacer server $ENV{"APP_WEB_1_PORT_5000_TCP_ADDR"}:5000; par server app_web_1:5000;

1 votes

Merci @mozz100 - c'est incroyablement utile - les entrées /etc/hosts sont beaucoup plus efficaces que les variables d'environnement dans ce cas. La seule chose qui manque, c'est ce qui se passe si le conteneur amont est redémarré et acquiert une nouvelle adresse IP. Je suppose que les conteneurs enfants pointeront toujours vers l'adresse IP d'origine, pas la nouvelle ?

1 votes

Oui, si vous redémarriez app_web_1, il recevrait une nouvelle adresse IP, vous devriez donc redémarrer votre conteneur nginx aussi. Docker le redémarrerait avec un /etc/hosts mis à jour, vous n'auriez donc pas besoin de modifier le(s) fichier(s) de configuration nginx.

197voto

Omid Raha Points 1837

Depuis le fichier docker officiel de Nginx :

Utilisation de variables d'environnement dans la configuration de nginx :

Par défaut, Nginx ne prend pas en charge l'utilisation de variables d'environnement à l'intérieur de la plupart des blocs de configuration.

Mais envsubst peut être utilisé comme un contournement si vous avez besoin de générer votre configuration nginx dynamiquement avant le démarrage de nginx.

Voici un exemple utilisant 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;'" 

Le fichier mysite.template peut alors contenir des références de variables comme ceci :

listen ${NGINX_PORT};

Mise à jour :

Mais vous savez que ceci a causé ses variables Nginx à être comme ceci :

proxy_set_header        X-Forwarded-Host $host;

endommagé en :

proxy_set_header        X-Forwarded-Host ;

Alors, pour prévenir cela, j'utilise ce petit truc :

J'ai un script pour exécuter Nginx, qui est utilisé dans le fichier docker-compose comme option de commande pour le serveur Nginx, je l'ai nommé run_nginx.sh :

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

Et en raison de la définition de la nouvelle variable DOLLAR dans le script run_nginx.sh, maintenant le contenu de mon fichier nginx.conf.template pour la variable Nginx elle-même est comme ceci :

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

Et pour ma variable définie c'est comme ceci :

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

Aussi, ici, il y a mon vrai cas d'utilisation pour cela.

4 votes

Cela tue les configurations nginx comme proxy_set_header Host $http_host;

0 votes

@shredding pourriez-vous élaborer? pourquoi?

0 votes

@shredding ok, je viens de rencontrer le même problème :( avez-vous trouvé un moyen de contourner cela? J'ai ouvert un problème: github.com/docker-library/docs/issues/496

108voto

Sadly Not Points 16959

L'image nginx officielle recommande d'utiliser envsubst, mais comme d'autres l'ont souligné, cela remplacera également $host et d'autres variables, ce qui n'est pas souhaitable. Heureusement, envsubst peut prendre en paramètre les noms des variables à remplacer.

Pour éviter un paramètre de commande très complexe pour le conteneur (comme dans l'exemple lié), vous pouvez écrire un script d'entrée Docker qui remplira les variables d'environnement avant d'exécuter la commande. Le script d'entrée est également un bon endroit pour valider les paramètres et définir des valeurs par défaut.

Voici un exemple d'un conteneur nginx qui prend en compte les paramètres API_HOST et API_PORT en tant que variables d'environnement.

nginx-default.conf.template

resolver  127.0.0.11 valid=10s;  # récupérer le changement IP du backend

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

3 votes

J'ai légèrement modifié le script pour nettoyer le modèle de conf.d. Version finale: ``` #!/usr/bin/env sh set -eu envsubst '${API_HOST} ${API_PORT}' < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf rm /etc/nginx/conf.d/default.conf/template exec "$@" ``` super script cependant merci!

0 votes

Je suis curieux de savoir pourquoi nginx a rendu cela si compliqué.

1 votes

L'image officielle dispose désormais d'une variable d'environnement supplémentaire pour éviter de remplacer les variables non désirées : NGINX_ENVSUBST_FILTER. C'est une expression régulière, et les variables ne correspondant pas ne seront pas remplacées. Vous pouvez le définir par exemple à API_ via docker-compose.yml ou Dockerfile pour laisser intactes les variables telles que $host. Cela élimine le besoin d'un script d'entrée personnalisé. Voir github.com/nginxinc/docker-nginx/pull/706 pour plus de détails.

69voto

Martin Points 633

envsubst est désormais géré automatiquement par l'image nginx.

Depuis la documentation:

Par défaut, nginx ne prend pas en charge les variables d'environnement à l'intérieur de la plupart des blocs de configuration. Mais cette image dispose d'une fonction, qui extraira les variables d'environnement avant le démarrage de nginx.

Par défaut, cette fonction lit les fichiers de modèle dans /etc/nginx/templates/*.template et affiche le résultat de l'exécution de envsubst dans /etc/nginx/conf.d.

0 votes

C'est génial! Mais, je ne le vois pas se produire. J'ai mis un fichier .template dans /etc/nginx/templates/, mais rien n'est écrit dans /etc/nginx/conf.d. J'utilise l'image docker nginx:1.19.2. J'ai un script d'entrée personnalisé, mais il finit par appeler nginx -g 'daemon off;'. Est-ce que je rate quelque chose?

2 votes

@JohnL Je n'ai pas regardé en détail, mais il semble que cette action soit réalisée via un script inclus dans le Dockerfile. Vous devrez exécuter ce script pour utiliser cette fonctionnalité

3 votes

Il s'agit de la nouvelle réponse acceptée. Fonctionne à merveille.

56voto

Faire cela avec Lua est considérablement plus facile que cela n'en a l'air :

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

J'ai trouvé ça ici :

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

Modifier :

Apparemment, cela nécessite l'installation du module Lua : https://github.com/openresty/lua-nginx-module

Modifier 2 :

Notez qu'avec cette approche, vous devez définir la variable env dans Nginx :

env ENVIRONMENT_VARIABLE_NAME

Vous devez le faire dans le contexte de niveau supérieur de nginx.conf ou cela ne fonctionnera pas ! Pas dans le bloc server ou dans la configuration de certains sites dans /etc/nginx/sites-available, car elle est incluse par nginx.conf dans le contexte http (qui n'est pas un contexte de niveau supérieur).

Remarquez également qu'avec cette approche, si vous essayez de faire une redirection par exemple :

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

cela ne fonctionnera pas non plus :

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

Et si vous lui donnez un nom de variable distinct :

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 ne l'interprétera pas et vous redirigera vers https://%24server_name_from_env/.

3 votes

Vous pouvez avoir besoin de env NGINX_SERVERNAME quelque part dans votre nginx.conf.

0 votes

Cela n'a pas fonctionné pour moi, bien que j'aie le module lua dans mon image docker nginx. Cela pourrait-il être lié au fait que j'inclus un fichier de configuration dans mon nginx.conf ? J'essayais de set_by_lua la variable dans le fichier de configuration inclus, alors que la déclaration env MY_VAR était dans le fichier nginx.conf principal, comme suggéré. Quel dommage, cela aurait été la solution la plus propre!

0 votes

Quelqu'un connaît les avantages/inconvénients de l'utilisation de cette méthode de envsubst? Je suppose que l'avantage est que vous n'avez pas besoin d'exécuter la commande envsubstr avant de démarrer le serveur et l'inconvénient est que vous devez installer le module lua? Je me demande s'il y a des implications de sécurité sur l'une ou l'autre approche?

15voto

yawn Points 251

J'ai écrit quelque chose qui peut être utile ou non : https://github.com/yawn/envplate

Il édite en ligne des fichiers de configuration avec des références ${key} aux variables d'environnement, en créant éventuellement des sauvegardes / enregistrant ce qu'il fait. Il est écrit en Go et le binaire statique résultant peut être simplement téléchargé depuis l'onglet de sortie pour Linux et MacOS.

Il peut également exécuter() des processus, substituer des valeurs par défaut, enregistrer des journaux et possède des sémantiques d'échec sensées.

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X