63

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

schickling
  • 4,000
  • 4
  • 29
  • 33
  • You could also make a **bash templating** using `envsubst`. This without requiring docker or lua+perl as described in this question: https://stackoverflow.com/questions/2914220/bash-templating-how-to-build-configuration-files-from-templates-with-bash – c24b Feb 20 '20 at 13:15

6 Answers6

61

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

Michal Foksa
  • 11,225
  • 9
  • 50
  • 68
  • The link seems not to lead to where you probably wanted it to lead :) – HermanTheGermanHesse Sep 24 '19 at 06:52
  • 1
    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 – lance-java Feb 03 '22 at 08:45
  • Not a good idea, envsubst will substitute default env used by nginx. – protocod Mar 02 '22 at 13:50
  • 1
    The issue with using envsubst and Nginx variables (like $host) has a solution here: https://stackoverflow.com/questions/65277864/how-fix-nginx-error-invalid-number-of-arguments – Jesuisme Aug 05 '22 at 13:51
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

kikito
  • 51,734
  • 32
  • 149
  • 189
  • Is there a way to check the output when launching this config through a helm install? – Kajsa Feb 24 '20 at 09:08
  • 1
    @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). – kikito Feb 25 '20 at 09:08
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.

Ben Whaley
  • 32,811
  • 7
  • 87
  • 85
  • Thanks! But is there no option to use variables defined in `nginx.conf` in server blocks? – schickling Feb 19 '14 at 16:57
  • 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. – Ben Whaley Feb 19 '14 at 17:49
  • 2
    Saving people some time (the above requires a custom build), you can use a template and a tool called envsubst http://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``` – lsl Mar 03 '17 at 00:27
  • 1
    What is this `_from_env` suffix?? – Marc Jun 05 '21 at 07:13
17

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

Dharman
  • 30,962
  • 25
  • 85
  • 135
Ido Bleicher
  • 709
  • 1
  • 9
  • 19
  • 8
    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 :) – Hunter_71 Sep 04 '20 at 13:40
  • 5
    It is not a feature of nginx itself but of it's official docker container, description is here https://hub.docker.com/_/nginx in paragraph "Using environment variables in nginx configuration (new in 1.19)" – Ilya Kolesnikov Mar 13 '21 at 11:50
  • 2
    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`. – Tobias Nov 10 '21 at 17:13
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.

guyskk
  • 2,468
  • 1
  • 15
  • 13
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.

cigien
  • 57,834
  • 11
  • 73
  • 112