69

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

1
  • You could also make a bash templating using envsubst. This without requiring docker or lua+perl as described in this question: stackoverflow.com/questions/2914220/… Commented Feb 20, 2020 at 13:15

7 Answers 7

69

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

Sign up to request clarification or add additional context in comments.

4 Comments

The link seems not to lead to where you probably wanted it to lead :)
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 environment
Not a good idea, envsubst will substitute default env used by nginx.
The issue with using envsubst and Nginx variables (like $host) has a solution here: stackoverflow.com/questions/65277864/…
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

3 Comments

Is there a way to check the output when launching this config through a helm install?
@Kajsa 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).
It's worth noting, that most recent image versions do not include the Perl module by default. Therefore, you would need, for example, this image: nginx:1.27.2-alpine3.20-perl. Check out hub.docker.com/_/nginx for more information.
23

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://stackoverflow.com/a/62844707/4479861

3 Comments

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 :)
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)"
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.
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.

4 Comments

Thanks! But is there no option to use variables defined in nginx.conf in server blocks?
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.
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.$host
What is this _from_env suffix??
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.

Comments

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.

Comments

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.