8

If I use a environment variable in the nginx config, and nginx is configured to serve only static files (html,js,css - e.g. a AngularJs app), is there any way I can use the environment variable within a JS file that nginx serves? Or is the only way to do this to run a non-static server, e.g. io.js, php, etc.


Btw you can't use environment variables natively in nginx's configuration.

When I talk about environment vars in the nginx config I mean like in this post: How can I use environment variables in Nginx.conf where they use env APP_WEB_1_PORT_5000_TCP_ADDR; and $ENV{"APP_WEB_1_PORT_5000_TCP_ADDR"};


Explain exactly your use case

My specific use case is that I have a nginx-powered AngularJS app in a docker container. The app is a "Single Page Application" that consumes a API running on another system altogether. Currently I run a different docker container between production and staging because the app has some config that is different, for example the Google-Analtyics code. This environment-specific data is kept in a config.js file and the values are currently hardcoded, one value for the master branch in git, and different value for the staging branch. I want to change the design so I can use the same container for both production and staging. I want to pass a ENV var into the container when I run it (docker run -e GACODE=UA-12345-6 ...) and have nginx use the ENV var (via env GACODE; and $ENV{"GACODE"} so the config.js file can use the GoogleAnaltyics codes that are passed in, rather than hardcoding them). I don't know whether this is possible or not (hence the question ;)). Using only nginx makes my container a single-process, whereas if I have to use io.js then I'll need multiple linked containers and more moving parts is more complex).

  • What ?! Explain exactly your use case since it appears you are looking at it on the wrong side. Btw you can't use environment variables natively in nginx's configuration. – Xavier Lucas Mar 19 '15 at 13:47
  • Thanks @XavierLucas - I updated the question to try to explain more. – Tom Mar 19 '15 at 17:33
3

sub_filter

If you want a simple string-replace, you can use sub_filter. For example:

server {
    sub_filter "REPLACE_THIS" "with this";
    sub_filter_once off; # Don't stop at the first match, replace all of them
    sub_filter_types "text/javascript" "application/json"; # Apply to these mime types in addition to text/html 

    # Everything else
}

However it's not possible to read an environment variable in nginx config - you can of course script writing the nginx config file any way you need/want to produce a valid config file and then reload nginx.

1

I experimented with using sub_filter and nginx environment variables but concluded that it isn't possible.

For example, this shows my experiments and shows using ENVs passed to nginx does not work within a server block:

env TOMTEST1; # OK - makes $ENV{"TOMTEST1"} available but NOT in server block.

http {

    server {

        # set $TOMTEST1 $ENV{"TOMTEST1"};    # KO - DOES NOT WORK - NGINX WONT START
        set $TOMTEST2   'tomtest2 Var';      # OK - THIS DOES WORK OK

        sub_filter 'TOM_TEST2' $TOMTEST2;       # OK - but not useful to me.
        sub_filter 'TOM_TEST3' 'tomtest3 Var';  # OK - but not useful to me.
        sub_filter_once off;                    # Don't stop at the first match, replace all of them
        sub_filter_types "text/javascript" "application/json"; # Apply to these mime types in addition to text/html

        # Serve static files
        location / {
           try_files $uri /index.html =404;
        }
        ...

where the static config.json file that I'm serving has various test strings like the following:

{
    "environment": "local",
    "test1": "$ENV{"TOMTEST1"}",
    "test3": "TOM_TEST2",
    "test4": "TOM_TEST3",
}

As @AD7six mentioned, the way to proceed is have a script that runs before nginx starts to produce a valid config file from placeholders. But this begs the question, if a script is going to run before nginx starts, I may as well set the contents of my config.json file in that script and not bother with sub_filter at all.

  • 1
    If it's for one static file - it certainly makes sense to not do it via nginx config, I assumed your usecase was a bit broader than that. For info/contrast I use sub_filter "example.com" "example.dev"; in a dev setup to replace any and all references to the production domain to the local environment because those references come from 3rd party api responses/app code/js/db dumps/etc. - i.e. for nginx it could be anywhere in any html/js/json response. +1 – AD7six Mar 26 '15 at 9:53
1

I've been looking into resolving the same issue as the OP and this post came up in Google search, so thought I'd add a potential solution.

This post outlines how you can expose an environment variable within nginx config: https://blog.doismellburning.co.uk/environment-variables-in-nginx-config/

And you can return content without having a file in the file system: Reply with 200 from Nginx config without serving a file

Putting these two things together we end up with the following:

env MY_ENV_VAR;

# Snip

http {
    # Snip

    server {
        # Snip

        location ~ ^/config.js$ {
            add_header Content-Type text/javascript;
            set_by_lua $env_var 'return os.getenv("MY_ENV_VAR")';
            return 200 'const MY_ENV_VAR = \'$env_var\'';
        }
    }
}

This has worked for me in a test environment. It's a little cumbersome (not sure it's better than auto-generating a file on Docker launch that contains the vars you need).

Hope that helps.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.