Using Env Variables in NGINX Configuration
How do you set up an NGINX server configuration to use a single config file for a multi-environment setup without having different config files for each environment?
Currently, NGINX does not support dynamic configurations. Let’s take a simple yet common scenario where the NGINX configuration needs to be slightly different for the development and production environments; development listens to port 8080 on the localhost domain, and production listens to port 80 on the example.com domain.
Let’s take the following production configuration: a PHP server listening to port 80 on the example.com domain.
nginx.config
...
http {
...
server {
listen 80;
server_name www.example.com;
...
locatiion ~ ^/assets/ {
...
}
location ~ \.php$ {
...
}
}
}
To use the same configuration in the development environment, you must make a copy and change the port and
host settings. You could break up the configuration file into parts and use the include
directive.
However, no matter what you do, you’ll have to manage multiple configurations for each environment.
To throw another wrench into the mix, how would you handle:
- Developers wanting to use different ports or host settings?
- Continues Integration and Deployment with feature branches?
- Other quality control pipelines?
The more environments you have to account for, the more likely a tiny change will end up breaking downstream.
To solve this, you can make a template out of the configuration file and use
envsubst
to replace the
desired environment variables in the template.
We can change the above configuration example by replacing the port with the environment variable $PORT
and
the host with the environment variable $HOST
.
nginx.config.template
...
http {
...
server {
listen $PORT;
server_name $HOST;
...
locatiion ~ ^/assets/ {
...
}
location ~ \.php$ {
...
}
}
}
Using the following shell script, we can configure the NGINX server based on the environment it is running in.
update-nginx-config.sh
#!/usr/bin/env sh
set -eu
envsubst '\$PORT \$HOST' < /etc/nginx/nginx.conf.template > /etc/nginx/nginx.conf
I love this approach because of how simple it is. It is easy to test and add other configurations, such as HTTP header values and proxy locations.
Have you implemented something similar? Let me know; I would love to hear from you.