Nginx.conf에서 환경 변수를 사용하는 방법


183

[ CrossOverflow에 대해 sysadmin과 같은 것으로 간주 되어 https://stackoverflow.com/questions/21933955 에서 교차 게시 및 편집되었습니다 .]

Nginx를 실행하는 도커 컨테이너가 있는데 다른 도커 컨테이너에 연결됩니다. 두 번째 컨테이너의 호스트 이름과 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

8
이것은 환경 변수에 대한 일반적인 솔루션은 아니지만 업스트림 서버의 호스트 이름 / IP 주소에 환경 변수를 사용하려는 경우 Docker (최소 최신 버전에서는)가 / etc / hosts를 수정합니다. docs.docker.com/userguide/dockerlinks를 참조하십시오. 즉, 연결된 컨테이너가 'app_web_1'인 경우 docker는 Nginx 컨테이너의 / etc / hosts에 줄을 만듭니다. 따라서 다음 server $ENV{"APP_WEB_1_PORT_5000_TCP_ADDR"}:5000; 과 같이 대체 할 수 있습니다 server app_web_1:5000;
mozz100

1
감사합니다 @ mozz100-매우 유용합니다-이 경우 / etc / hosts 항목이 env vars보다 훨씬 효과적입니다. 유일하게 누락 된 부분은 업스트림 컨테이너가 다시 시작되고 새로운 IP를 얻는 경우에 발생합니다. 하위 컨테이너가 여전히 새 IP가 아닌 원래 IP를 가리킬 것이라고 생각합니까?
Hugo Rodger-Brown

1
예, 다시 시작 app_web_1하면 새 IP 주소가 생성되므로 nginx 컨테이너도 다시 시작해야합니다. Docker는 업데이트로 다시 시작 /etc/hosts하므로 nginx 구성 파일을 변경할 필요가 없습니다.
mozz100

답변:


100

에서 공식 Nginx에 고정 표시기 파일 :

nginx 구성에서 환경 변수 사용 :

기본적으로 Nginx는 대부분의 구성 블록 내에서 환경 변수 사용을 지원하지 않습니다.

그러나 envsubstnginx가 시작되기 전에 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 ;

그래서 그것을 막기 위해이 트릭을 사용합니다.

docker-compose파일에서 Nginx 서버의 명령 옵션으로 사용되는 Nginx를 실행하는 스크립트가 있습니다 run_nginx.sh.

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

그리고 스크립트에 새로운 DOLLAR변수 가 정의 run_nginx.sh되었으므로 이제 nginx.conf.templateNginx 자체 변수에 대한 파일 내용 은 다음과 같습니다.

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

그리고 정의 된 변수는 다음과 같습니다.

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

또한 여기 에는 실제 사용 사례가 있습니다.


2
그것은 nginx confs를 죽입니다proxy_set_header Host $http_host;
파쇄

22
: 다른 사람이 감동하지 않습니다 - 당신은 변수 이름에 전달할 수 있습니다 @shredding은 교체 할 command: /bin/bash -c "envsubst '$VAR1 $VAR2' < /etc/nginx/conf.d/mysite.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"나는 그들이이라고 알고 / c를 ... b를 나를 위해 작동
pkyeck

4
좋아, 탈출하는 것을 잊었다 $이어야한다command: /bin/bash -c "envsubst '\$VAR1 \$VAR2' < /etc/nginx/conf.d/mysite.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"
pkyeck

2
탈출을 고려하여 자신의 Dockerfile에서 작동합니다.CMD ["/bin/sh","-c", "if [ -n \"${SOME_ENV}\" ]; then echo envsubst '${SOME_ENV}' with ${SOME_ENV} && envsubst '${SOME_ENV}' < /etc/nginx/conf.d/default.template > /etc/nginx/conf.d/default.conf; fi ; nginx -g 'daemon off;'"]
KCD

1
이것은 훌륭한 솔루션입니다. 감사. 또한 위에서 언급 한 github.com/docker-library/docs/issues/496 링크 는이 문제에 대한 훌륭한 솔루션을 제공합니다.
kabirbaidhya

34

루아와 함께하는 것이 소리보다 훨씬 쉽습니다.

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 :

이 접근법을 사용하면 envNginx에서 변수 를 정의해야합니다 .

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/.


3
env NGINX_SERVERNAMEnginx.conf 어딘가에 필요할 수 있습니다 .
hiroshi

내 nginx docker 이미지에 lua 모듈이 있지만 이것은 나를 위해 작동하지 않았습니다. 이것이 nginx.conf에 구성 파일을 포함한다는 사실과 관련이 있습니까? set_by_lua포함 된 구성 파일의 변수를 시도 했지만 env MY_VAR선언은 제안 된대로 기본 nginx.conf에있었습니다. 얼마나 부끄러운 일입니까? 이것이 가장 깨끗한 해결책이었습니다!
pederpansen

누구 든지이 방법을 사용하는 장단점을 알고 envsubst있습니까? 나는 envsubstr서버를 시작하기 전에 명령 을 실행할 필요가 없으며 lua 모듈을 설치해야한다는 것이 전문가라고 생각합니다 . 두 가지 접근 방식에 보안 관련이 있는지 궁금합니다.
Mark Winterbottom

@MarkWinterbottom는 아직 테스트하지 않았지만, 당신은 당신이 사용하는있는의 nginx 설정 파일에 쓰기 권한을 부여하지 않았을 것 같습니다 envsubst하고있는 것은 내 경우에는 이동 중입니다
Griddo

14

도움이되거나 도움이되지 않을 수있는 것을 썼습니다 : https://github.com/yawn/envplate

환경 변수에 대한 $ {key} 참조를 사용하여 구성 파일을 인라인 편집하여 선택적으로 백업을 작성하고 수행하는 작업을 로깅합니다. Go로 작성되었으며 Linux 및 MacOS의 릴리스 탭에서 정적 바이너리를 간단히 다운로드 할 수 있습니다.

또한 exec () 프로세스, 대체 기본값, 로그 및 합리적인 의미 체계가 있습니다.


10

공식의 nginx 이미지 사용을 권장envsubst 하지만, 다른 사람에 의해 지적 또한 대체합니다 $host및 바람직하지 않다 다른 변수. 그러나 다행히 변수 이름을 대체 할 매개 변수로envsubst 사용할 수 있습니다 .

컨테이너에 대한 매우 복잡한 명령 매개 변수를 피하려면 (연결된 예에서와 같이) 명령을 실행하기 전에 환경 변수를 채우는 Docker 진입 점 스크립트를 작성할 수 있습니다. 진입 점 스크립트는 매개 변수를 확인하고 기본값을 설정하는 데에도 적합합니다.

여기 취하는 Nginx의 용기의 예 API_HOSTAPI_PORT환경 변수로 매개 변수.

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 "$@"

도커 파일

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

5

내가 한 것은 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
}

4

erb 사용에 대한 답변을 참조하면 다음과 같이 할 수 있습니다.

NGINX 구성 파일을 환경 변수가 포함 된 erb 파일로 작성하고 erb 명령을 사용하여 일반 구성 파일로 평가하십시오.

erb nginx.conf.erb > nginx.conf

nginx.conf.erb 파일의 서버 블록 안에는

listen <%= ENV["PORT"] %>;

1
컨테이너 내부에 Ruby를 설치해야합니까? (아니라면 erb컨테이너를 시작한 후 변수 대체를 어떻게 할 수 있을까요?) — erb루비가 맞습니까? stuartellis.name/articles/erb
KajMagnus

1
표준 Ruby 설치와 함께 제공되는 명령 줄 도구입니다. 컨테이너에없는 다른 옵션을 사용해보십시오.
Ruifeng Ma

3

나는 이것이 오래된 질문이라는 것을 알고 있지만 누군가 내가 이것에 걸려 넘어지는 경우를 대비하여 훨씬 더 좋은 방법이 있습니다. docker는 / etc / hosts에 연결된 컨테이너의 별칭을 삽입하기 때문에 할 수 있습니다.

upstream upstream_name {
    server docker_link_alias;
}

docker 명령을 가정하면과 같습니다 docker run --link othercontainer:docker_link_alias nginx_container.


1
이 방법을 사용하여 호스트를 얻을 수 있지만 포트는 얻을 수 없습니다. 포트를 하드 코딩하거나 포트 80을 사용한다고 가정해야합니다.
Ben Whaley

2

또 다른 옵션 ... 오늘 방금이 도구를 찾았습니다 : https://github.com/kreuzwerker/envplate ... Go로 작성되었으며 매우 쉽게 설치할 수 있습니다. 그것을 사용하는 것은 매우 간단합니다. nginx.conf에 템플릿 변수를 배치해야합니다.

예를 들어 ${SOME_ENV_VAR}envplate의 ep명령이 파일에서 호출 되면 대체됩니다 . 따라서 Dockerfile이 해당 바이너리를 얻지 못하거나 어떤 이유로 실행되지 않으면 구성이 유효하지 않게됩니다. 펄 또는 루아 확장을 사용하는 것과 같은 다른 솔루션과 비교할 때 약간의 메모입니다.

환경 변수가 설정되지 않은 경우 기본값을 설정하는 방법도 정말 좋습니다. 전의. ${SOME_ENV_VAR:default-value}(그리고 당신은 값을 벗어날 수 있습니다). 다시 envplate은 여전히 ​​성공적으로 실행되어야합니다.

이와 같은 접근 방식을 사용하면 얻을 수있는 이점 중 하나는 필요하지 않은 모든 종류의 추가 모듈을 설치하지 않았기 때문에 필요한 것보다 큰 Docker 이미지로 끝나지 않는다는 것입니다. 상황이 복잡해지고 기본 기능이 포함되어 있으면 sed를 사용하는 것보다 쉬울 수도 있습니다.


나는 조언 github.com/gliderlabs/sigil 나는 많은 버그와 envplate 문제로 실행한다.
Nick

2

쉘 스크립트를 사용 하여이 작업을 수행합니다.

다음은 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;'

1

또 다른 가능성은 정규 표현식과 함께 'sed'명령을 사용하는 것이므로 구성 파일을 전혀 망칠 필요가 없습니다! 그렇게하면 구성 파일을 정상적으로 사용할 수 있지만 docker를 실행하면 env 변수와 값이 바뀝니다. 이 중 어느 것도 "검색하고 바꿀 구성 파일에 텍스트 문자열을 추가하지 않습니다."

환경 변수를 사용하여 대체 값으로 run.sh 파일을 작성할 수 있습니다.

이 줄에서 "7s"를 변경하려면 :

client_body_timeout 7s;         #Default 60s

나오지도 명령 사용 client_body_timeout 검색 선으로 및 $ client_body_timeout 교체 ENV 변수로 :

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

설정하려는 모든 매개 변수에 대해이 행을 복사하여 붙여넣고 config 옵션을 사용하여 client_body_timeout을, 연관된 env 변수를 사용하여 $ client_body_timeout을 변경하십시오. 기존 구성 파일과 함께 사용하면 작동합니다.


0

sed방법 을 사용하는 예는 다음과 같습니다. 반드시 더 좋은 것은 아니지만 일부에게는 유용 할 수 있습니다. 먼저 conf 파일 내에서 교체 할 사용자 정의 키워드를 추가하십시오. 둘째, ENV변수 를 선언하는 dockerfile을 생성 한 다음 nginx를 명시 적으로 실행하기 전에 구성을 편집 CMD하는 데 사용 하는 dockerfile을 만듭니다 sed.

따라서 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

0

위의 대답이 부실하기 때문에 루아 로이 작업을 수행하는 올바른 방법입니다.

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


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.