1. Overview

Sometimes, we need our server to run in different modes and use different resources. For instance, we might need to use different resources for testing and running our server in production. Therefore, using environment variables is a sound solution to these kinds of problems.

nginx.conf contains config related to our Nginx server. The Nginx config doesn’t support environment variables out of the box. However, there are tools and workarounds that we can use to carry out this process for us.

In this article, we’ll discuss how we can use environment variables in nginx.conf. Additionally, our approach will apply to running the server in a container and directly.

2. Using envsubst

envsubst is a tool that we can use to generate an Nginx config file dynamically before the server starts. It replaces variables in a text with the corresponding values of our shell variables.

Moreover, it’s not a standalone utility. It comes with the gettext metapackage. So, by default, it will already be available on our Linux machine.

2.1. Basic Usage

We’ll create a simple file that contains the $PWD variable:

$ echo "I am inside $PWD directory" > printdir.txt

Of course, we can put as many shell variables in the text file as we need. Now, when we print this file, it prints the $PWD literally:

$ cat printdir.txt
I am inside $PWD directory

Let’s replace it with the actual value of $PWD using envsubst:

$ envsubst < printdir.txt
I am inside /home/hey directory

Having this knowledge at our disposal, we can create a dynamic Nginx config file that contains environment variables instead of hardcoded values.

2.2. Nginx Config With envsubst

First, we’ll need to create a template for our Nginx config that will contain the environment variable references.

Let’s create a minimal config template with placeholders:

http {
  server {
    server_name ${SERVER_NAME};
    listen ${HOST}:${PORT};
    error_page 500 502 503 504 /50x.html;
    location / {
      root html;
    }
  }
}

We’ll save this with the filename my-site.conf.template.

Next, we’ll export our required environment variables in the current shell session:

$ export SERVER_NAME=localhost
$ export HOST=127.0.0.1
$ export PORT=80

We can now use our template and run Nginx:

$ envsubst < /etc/nginx/conf.d/my-site.conf.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'

Let’s break it down:

  • we fed the contents of my-site.conf.template to the envsubst command
  • the output of envsubst is written to the default.conf file
  • we started our server using the nginx command

By default, Nginx uses the default.conf if no config file is specified.

Let’s check default.conf to verify that our variables are referenced correctly:

$ cat /etc/nginx/conf.d/default.conf
http {
  server {
    server_name localhost;
    listen 127.0.0.1:80;
    error_page 500 502 503 504 /50x.html;
    location / {
      root html;
    }
  }
}

2.3. Docker Compose

We can use the same concept when using Docker Compose. In the docker-compose.yml file, we’ll specify our environment variables.

Afterward, we’ll specify the command that creates our config file and starts the server:

image: nginx
volumes:
 - ./my-site.tmpl:/etc/nginx/conf.d/my-site.conf.template
ports:
 - "8080:80"
environment:
 - HOST=my-site.com
 - PORT=80
 - SERVER_NAME="my-site"
command: /bin/bash -c "envsubst < /etc/nginx/conf.d/my-site.conf.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"

The official image now supports environment variables through envsubst out of the box. However, this approach also applies to other custom images that make use of Nginx.

2.4. A Common Pitfall

This method looks effective for our simple config. However, the problem arises when we use the Nginx built-in environment variables such as $host and $connection.

As we can guess, it will create a conflict with our environment variables.

For instance, if we have this statement:

proxy_set_header  X-Forwarded-Host $host;

After using envsubst, it yields the following result:

proxy_set_header  X-Forwarded-Host ;

Fortunately, we can remedy this by using a simple shell script:

#!/usr/bin/env bash
export DOLLAR="$"
envsubst < /etc/nginx/conf.d/my-site.conf.template > /etc/nginx/conf.d/default.conf
nginx -g "daemon off;"

In our template, we can reference the dollar signs with ${DOLLAR}:

proxy_set_header X-Forwarded-Host ${DOLLAR}host;

Basically, when our template goes through envsubst, it produces $host. In turn, Nginx recognizes this as the built-in variable.

Alternatively, we can also specify the exact names of the environment variables to process:

$ envsubst "\$VAR1 \$VAR2" < my-site.conf.template > default.conf

Similarly, in our docker-compose.yml file, we can escape the dollar sign using $$:

...
command: /bin/bash -c "envsubst '$${VAR1} $${VAR2}' < /etc/nginx/conf.d/my-site.conf.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"
...

This way, all the other variables that start with $ won’t be affected.

3. Using Lua Nginx Module

OpenResty is a platform that extends the functionality of the Nginx server. It ships with modules that we can use in our Nginx server. Additionally, it also includes the Lua Nginx module.

With the Lua Nginx module, it’s pretty straightforward to use environment variables inside our Nginx config.

We must declare our environment variables at the very top of our base Nginx config:

env SERVER_NAME;
env HOST;
env PORT

http {
...
}

Afterward, we can simply use these variables:

http {
  server {
    set_by_lua server_name 'return os.getenv("SERVER_NAME")';
    set_by_lua listen 'return os.getenv("HOST")':'return os.getenv("PORT")';
    error_page 500 502 503 504 /50x.html;
    location / {
      root html;
    }
  }
}

4. Conclusion

In this article, we discussed how we can use environment variables inside the Nginx config file. We used the envsubst utility to generate our config dynamically from a template file.

Additionally, we also saw how we can handle Nginx built-in variables during substitution.

Finally, we covered the Lua Nginx module as an alternative solution.

Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.