nginx: use environment variables
Asked Answered
M

7

68

I have the following scenario: I have an env variable $SOME_IP defined and want to use it in a nginx block. Referring to the nginx documentation I use the env directive in the nginx.conf file like the following:

user www-data;
worker_processes 4;
pid /run/nginx.pid;

env SOME_IP;

Now I want to use the variable for a proxy_pass. I tried it like the following:

location / {
    proxy_pass http://$SOME_IP:8000;
}

But I end up with this error message: nginx: [emerg] unknown "some_ip" variable

Morena answered 18/2, 2014 at 22:5 Comment(1)
You could also make a bash templating using envsubst. This without requiring docker or lua+perl as described in this question: #2914720Hiroshima
R
19

The correct usage would be $SOME_IP_from_env, but environment variables set from nginx.conf cannot be used in server, location or http blocks.

You can use environment variables if you use the openresty bundle, which includes Lua.

Roundup answered 19/2, 2014 at 16:28 Comment(4)
Thanks! But is there no option to use variables defined in nginx.conf in server blocks?Morena
In a server block you an use the syntax set $var "value"; and then refer to $var throughout your configuration. But you cannot use env vars.Roundup
Saving people some time (the above requires a custom build), you can use a template and a tool called envsubst serverfault.com/a/755541/116508 did this for docker and it works, just specify the env vars or you might wipe out vars in nginx unintentionally e.g.$hostPortraiture
What is this _from_env suffix??Daryn
C
64

With NGINX Docker image

Apply envsubst on template of the configuration file at container start. envsubst is included in official NGINX docker images.

Environment variable is referenced in a form $VARIABLE or ${VARIABLE}.

nginx.conf.template:

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    server {
        listen       80;
        location / {
            access_log off;
            return 200 '${MESSAGE}';
            add_header Content-Type text/plain;
        }
    }
}

Dockerfile:

FROM nginx:1.17.8-alpine
COPY ./nginx.conf.template /nginx.conf.template
CMD ["/bin/sh" , "-c" , "envsubst < /nginx.conf.template > /etc/nginx/nginx.conf && exec nginx -g 'daemon off;'"]

Build and run docker:

docker build -t foo .
docker run --rm -it --name foo -p 8080:80 -e MESSAGE="Hellou World" foo

NOTE:If config template contains dollar sign $ which should not be substituted then list all used variables as parameter of envsubst so that only those are replaced. E.g.:

CMD ["/bin/sh" , "-c" , "envsubst '$USER_NAME $PASSWORD $KEY' < /nginx.conf.template > /etc/nginx/nginx.conf && exec nginx -g 'daemon off;'"]

Nginx Docker documentation for reference. Look for Using environment variables in nginx configuration.

Using environment variables in nginx configuration

Out-of-the-box, nginx doesn’t support environment variables inside most configuration blocks. But envsubst may be used as a workaround if you need to generate your nginx configuration dynamically before nginx starts.

Here is an example using docker-compose.yml:

web:
  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 && exec nginx -g 'daemon off;'"

The mysite.template file may then contain variable references like this:

listen ${NGINX_PORT};

Coast answered 11/9, 2019 at 14:58 Comment(4)
The link seems not to lead to where you probably wanted it to lead :)Moten
Unfortunately my nginx.conf contained some dollar signs which I didn't want replaced so had to pass an explicit list to envsubst . Would be nice if envsubst was smart enough to only replace values which are set in the environmentFloatplane
Not a good idea, envsubst will substitute default env used by nginx.Spurgeon
The issue with using envsubst and Nginx variables (like $host) has a solution here: #65278364Bruise
R
35

You can access the variables via modules - I found options for doing it with Lua and Perl.

Wrote about it on my company's blog:

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

The TL;DR:

env API_KEY;

And then:

http {
...
  server {
    location / {
      # set var using Lua
      set_by_lua $api_key 'return os.getenv("API_KEY")';

      # set var using perl
      perl_set $api_key 'sub { return $ENV{"API_KEY"}; }';
      ...
    }
  }
}

EDIT: original blog is dead, changed link to wayback machine cache

Rundell answered 11/7, 2014 at 11:24 Comment(2)
Is there a way to check the output when launching this config through a helm install?Deyoung
@Deyoung you might want to make that comment into a SO question (with proper tags like helm etc). It will get more visibility and more chances of being answered by someone with Helm knowledge (which I am not).Rundell
R
21

Since nginx 1.19 you can now use environment variables in your configuration with docker-compose. I used the following setup:

# file: docker/nginx/templates/default.conf.conf
upstream api-upstream {
    server ${API_HOST};
}


# file: docker-compose.yml
services:
    nginx:
        image: nginx:1.19-alpine
        environment:
            NGINX_ENVSUBST_TEMPLATE_SUFFIX: ".conf"
            API_HOST: api.example.com

I found this answer on other thread: https://mcmap.net/q/282161/-substitute-environment-variables-in-nginx-config-from-docker-compose

Regeneracy answered 2/8, 2020 at 11:11 Comment(3)
It's worth to mention, that: 1) it uses a template files 2) template files should be created inside /etc/nginx/templates/ with defined suffix 3) after replacing env vars it automatically creates target configuration file inside conf.d without suffix (conf.d/default.conf for this example) 4) default template extension is .template 5) more can be found inside original answer :)Illuminance
It is not a feature of nginx itself but of it's official docker container, description is here hub.docker.com/_/nginx in paragraph "Using environment variables in nginx configuration (new in 1.19)"Mande
I like that solution, however it didn't work at the beginning, although I followed @Hunter_71's tips. That's because the Docker container has to start the docker-entrypoint.sh script in order to run envsubst which does the actual replacement. I had a CMD command defined in my Dockerfile, which makes the default ENTRYPOINT obsolete. Removing my CMD and placing it in a script which I copied to the /docker-entrypoint.d/ directory resolved the issue. Scripts in that directory are automatically executed by the default docker-entrypoint.sh.Hassler
R
19

The correct usage would be $SOME_IP_from_env, but environment variables set from nginx.conf cannot be used in server, location or http blocks.

You can use environment variables if you use the openresty bundle, which includes Lua.

Roundup answered 19/2, 2014 at 16:28 Comment(4)
Thanks! But is there no option to use variables defined in nginx.conf in server blocks?Morena
In a server block you an use the syntax set $var "value"; and then refer to $var throughout your configuration. But you cannot use env vars.Roundup
Saving people some time (the above requires a custom build), you can use a template and a tool called envsubst serverfault.com/a/755541/116508 did this for docker and it works, just specify the env vars or you might wipe out vars in nginx unintentionally e.g.$hostPortraiture
What is this _from_env suffix??Daryn
K
1

For simple environment variables substitution, can use the envsubst command and template feature since docker Nginx 1.19. Note: envsubst not support fallback default, eg: ${MY_ENV:-DefaultValue}.

For more advanced usage, consider use https://github.com/guyskk/envsub-njs, it's implemented via Nginx NJS, use Javascript template literals, powerful and works well in cross-platform. eg: ${Env('MY_ENV', 'DefaultValue')}

You can also consider https://github.com/kreuzwerker/envplate, it support syntax just like shell variables substitution.

Kidder answered 30/12, 2021 at 8:32 Comment(0)
G
0

If you're not tied to bare installation of nginx, you could use docker for the job.
For example nginx4docker implements a bunch of basic env variables that can be set through docker and you don't have to fiddle around with nginx basic templating and all it's drawbacks.

nginx4docker could also be extended with your custom env variables. only mount a file that lists all your env variables to docker ... --mount $(pwd)/CUSTOM_ENV:/ENV ...

When the worst case happens and you can't switch/user docker, a workaround maybe to set all nginx variables with their names (e.g. host="$host") in this case envsubst replaces $host with $host.

Gebhardt answered 20/5, 2022 at 13:15 Comment(0)
O
0

with podman & nginx docker image.

envsubst will be automatically executed when template file is in correct location /etc/nginx/templates in the nginx-container.

I added CSP (Content Security Policy) script-src hash to my nginx conf serving react app like this:

default.conf.template

server {
  listen 8080;
  root /usr/share/nginx/html;
  include /etc/nginx/mime.types;

  location / {
    add_header Content-Security-Policy "script-src 'self' '$CSP_SCRIPT_HASH' 'strict-dynamic'";
    try_files $uri $uri/ /index.html;
  }
}

Dockerfile

FROM nginx:1.23.4-alpine
COPY --from=build /opt/app/build /usr/share/nginx/html
COPY nginx/templates              /etc/nginx/templates/
EXPOSE 8080

Calling podman run with

podman run -e CSP_SCRIPT_HASH=sha256-wM+PPlLHcZenNEqjDFKpiuJrcOoeek6E0V5NxAro/Fc= --name mycontainername <my_nginx_image_app>

This should envsubst $CSP_SCRIPT_HASH with sha256-wM+PPlLHcZenNEqjDFKpiuJrcOoeek6E0V5NxAro/Fc=

You can run podman logs to see if envsubst is automatically executed

podman logs mycontainername 

output should have like this

/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
...
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
20-envsubst-on-templates.sh: Running envsubst on /etc/nginx/templates/default.conf.template to /etc/nginx/conf.d/default.conf
...
/docker-entrypoint.sh: Configuration complete; ready for start up

Log verify that envsubst is executed for /etc/nginx/templates/default.conf.template file and the result file is put into correct folder /etc/nginx/conf.d/default.conf

With this I can configure when deploying my container that which additional script CSP allow to be executed by giving the hash of the script as environment variable and it is applied in nginx conf.

Oversee answered 27/6 at 7:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.