Opened 5 years ago

Last modified 4 years ago

#1785 new enhancement

Support access to environment variables in config file

Reported by: spion-h4@… Owned by:
Priority: minor Milestone:
Component: other Version: 1.15.x
Keywords: Cc:
uname -a:
nginx -V: nginx version: nginx/1.10.3
built with OpenSSL 1.1.0f 25 May 2017 (running with OpenSSL 1.1.0j 20 Nov 2018)
TLS SNI support enabled
configure arguments: --with-cc-opt='-g -O2 -fdebug-prefix-map=/build/nginx-0TiIP5/nginx-1.10.3=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-z,relro -Wl,-z,now' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-ipv6 --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_geoip_module=dynamic --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module=dynamic --with-http_sub_module --with-http_xslt_module=dynamic --with-stream=dynamic --with-stream_ssl_module --with-mail=dynamic --with-mail_ssl_module --add-dynamic-module=/build/nginx-0TiIP5/nginx-1.10.3/debian/modules/nginx-auth-pam --add-dynamic-module=/build/nginx-0TiIP5/nginx-1.10.3/debian/modules/nginx-dav-ext-module --add-dynamic-module=/build/nginx-0TiIP5/nginx-1.10.3/debian/modules/nginx-echo --add-dynamic-module=/build/nginx-0TiIP5/nginx-1.10.3/debian/modules/nginx-upstream-fair --add-dynamic-module=/build/nginx-0TiIP5/nginx-1.10.3/debian/modules/ngx_http_substitutions_filter_module

Description

Currently nginx doesn't directly support access to environment variables in the config file. This makes it difficult to use it in a 12-factor-app style setup, where the docker container / VM / machine image use environment variables for configuring things such as static assets.

One way to work around this is to use envsubst to generate the config file on the fly. However, that means the target config file needs to be writable.

Another one would be to use something like ngx_http_lua_module. The process is two step: first, prevent the variable from being filtered out:

env MY_STATIC_ASSETS_PATH;

Then, set a variable using nginx syntax:

http {
...
  server {
    location /static {
      # set var using Lua
      set_by_lua $static_assets 'return os.getenv("MY_STATIC_ASSETS_PATH")';
      alias "$static_assets"
      ...
    }
  }
}

Since using the lua module seems heavy-handed for something like this, I'd like to propose a set_from_env directive that does exactly that. The result would be:

http {
...
  server {
    location /static {
      # set var using built in directive
      set_from_env $static_assets MY_STATIC_ASSETS_PATH;
      alias "$static_assets"
      ...
    }
  }
}

Change History (1)

comment:1 by edrandall@…, 4 years ago

+1 for this, here is our use-case:

In a kubernetes environment where we need a fixed configuration common across development, test and production environments. In Kubernetes any additional deployment-specific configuration is essentially passed to the application by environment variables set at startup.

Sometimes (this is just one example, there are other use cases) rewrites to environment-specific services are required, eg. dev must proxy for "service-X-dev" in dev, test for "service-X-tst" in test, and so forth - "service-X" might not even be in kubernetes yet. If our nginx config could read environment values, this can become straightforward and easy to understand.

I'm not saying there aren't other solutions to the above, but ability to configure map{...} output or variable value on the basis of an env variable can make this a lot easier. We don't really want to have pre-launch init script which reads the environment and generates a fragment of Nginx config file from it, it's a hacky solution and as the OP states, requires writing to the image filesystem.

We can't use the Lua module for info-security reasons - the whole point of choosing Nginx is for a small attack surface with minimal additional modules.

A directive something like this, probably in outermost context{...} scope, would likely suffice:

$variable = getenv('NAME', 'DEFAULT_VALUE');

This would then only get evaluated once when first used after startup and be available therafter in all child scopes.

Last edited 4 years ago by edrandall@… (previous) (diff)
Note: See TracTickets for help on using tickets.