I have a docker container running Nginx, that links to another docker container. The host name and IP address of the second container is loaded into the Nginx container as environment variables on startup, but is not know before then (it's dynamic). I want my nginx.conf
to use these values - e.g.
upstream gunicorn {
server $APP_HOST_NAME:$APP_HOST_PORT;
}
How can I get environment variables into the Nginx configuration on startup?
EDIT 1
This is the entire file, after the suggested answer below:
env APP_WEB_1_PORT_5000_TCP_ADDR;
# Nginx host configuration for django_app
# Django app is served by Gunicorn, running under port 5000 (via Foreman)
upstream gunicorn {
server $ENV{"APP_WEB_1_PORT_5000_TCP_ADDR"}:5000;
}
server {
listen 80;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
location /static/ {
alias /app/static/;
}
location /media/ {
alias /app/media/;
}
location / {
proxy_pass http://gunicorn;
}
}
Reloading nginx then errors:
$ nginx -s reload
nginx: [emerg] unknown directive "env" in /etc/nginx/sites-enabled/default:1
EDIT 2: more details
Current environment variables
root@87ede56e0b11:/# env | grep APP_WEB_1
APP_WEB_1_NAME=/furious_turing/app_web_1
APP_WEB_1_PORT=tcp://172.17.0.63:5000
APP_WEB_1_PORT_5000_TCP=tcp://172.17.0.63:5000
APP_WEB_1_PORT_5000_TCP_PROTO=tcp
APP_WEB_1_PORT_5000_TCP_PORT=5000
APP_WEB_1_PORT_5000_TCP_ADDR=172.17.0.63
Root nginx.conf:
root@87ede56e0b11:/# head /etc/nginx/nginx.conf
user www-data;
worker_processes 4;
pid /var/run/nginx.pid;
env APP_WEB_1_PORT_5000_TCP_ADDR;
Site nginx configuration:
root@87ede56e0b11:/# head /etc/nginx/sites-available/default
# Django app is served by Gunicorn, running under port 5000 (via Foreman)
upstream gunicorn {
server $ENV{"APP_WEB_1_PORT_5000_TCP_ADDR"}:5000;
}
server {
listen 80;
Reload nginx configuration:
root@87ede56e0b11:/# nginx -s reload
nginx: [emerg] directive "server" is not terminated by ";" in /etc/nginx/sites-enabled/default:3
From the official Nginx docker file:
Update:
But you know this caused to its Nginx variables like this:
damaged to:
So, to prevent that, i use this trick:
I have a script to run Nginx, that used on the
docker-compose
file as command option for Nginx server, i named itrun_nginx.sh
:And because of defined new
DOLLAR
variable onrun_nginx.sh
script, now content of mynginx.conf.template
file for Nginx itself variable is like this:And for my defined variable is like this:
Also here, there is my real use case for that.
The official nginx image recommends using
envsubst
, but as pointed out by others it will replace also$host
and other variables, which is not desirable. But fortunatelyenvsubst
can take as a parameter the names of variables to replace.To avoid a very complex command parameter to the container (as in the linked example), you can write a Docker entrypoint script which will fill in the environment variables before executing the command. The entrypoint script is also a good place for validating the parameters and setting default values.
Here is an example of an nginx container which takes in
API_HOST
andAPI_PORT
parameters as environment variables.nginx-default.conf.template
docker-entrypoint.sh
Dockerfile
envsubstr
is handled automatically by thenginx
image now.From the docs:
Doing this with Lua is substantially easier than it sounds:
I found that here:
https://docs.apitools.com/blog/2014/07/02/using-environment-variables-in-nginx-conf.html
Edit:
Apparently this requires installing the lua module: https://github.com/openresty/lua-nginx-module
Edit 2:
Note that with this approach you have to define
env
variable in Nginx:You have to do this in toplevel context in
nginx.conf
or it won't work! Not in server block or in config of some site in/etc/nginx/sites-available
, because it is included bynginx.conf
inhttp
context (which is not top-level context).Also note that with this approach if you try to make a redirect e.g.:
it won't work as well:
And if you give a separate variable name to it:
nginx won't interpret it and will redirect you to
https://%24server_name_from_env/
.I wrote something that may or may not be helpful: https://github.com/yawn/envplate
It inline edits configuration files with ${key} references to environment variables, optionally creating backups / logging what it does. It's written in Go and the resulting static binary can be simply downloaded from the release tab for Linux and MacOS.
It can also exec() processes, substitute defaults, logs and has sensible failure semantics.
What I did was to use the erb!
--After using erb
This is used in the Cloudfoundry staticfile-buildpack
Sample nginx configuration: https://github.com/cloudfoundry/staticfile-buildpack/blob/master/conf/nginx.conf
In your case
become
Referring to the answer on using erb, it can be done as below.
Write the NGINX config file as an erb file containing the environment variable, and evaluate it using the erb command to a normal config file.
Inside the server block of the nginx.conf.erb file there could be
I accomplish this using a shell script.
Here is the nginx template:
And the script to replace the environment variables is here:
There are many ways. Some have been outlined in some answers.
If you use the
ngx_http_js_module
, there is also a way to do that with JS:and
Please make sure you use njs module 0.33 or newer
Here's an example of using the
sed
approach, not necessarily better but it may be useful to some. First, add a custom keyword to be replaced within the conf file. Second, create a dockerfile that declares anENV
variable and then aCMD
that usessed
to edit the config before running nginx explicitly.So suppose your default.conf contains this with the keyword
docker_host
:And write your Dockerfile similar to:
Then build the image and run the container using