Setting up an NginX reverse proxy using domain names instead of IPs

April 01, 2020

Today I configured a reverse proxy using Nginx inside a Docker container, simple enough, right?

But what if the upstream server doesn’t have a static IP behind it? In cloud environments this might be the case.

The problem then lies in that Nginx resolves the domain name at start up, so if the IP changes later in the game, you proxy pass will be out of date.

So how can you sort this out? You have to use a combination of variables and resolve configuration files.

What you have to do:

  1. Extract the DNS resolver IP address from /etc/resolv.conf. Docker uses the default DNS resolver, but this is not always the case. In my case there was no easy way to figure out the DNS resolver IP address because of how the cloud settings are configured, so extracting it from the resolv.conf directly works fine.
  2. Replace it inside the Nginx configuration file.
  3. Make sure you are rebuilding the URL for the proxy_pass

The location block should look something like this:

location ~ ^/api/(.*)$ {
    resolver DOMAIN_DNS;
    set $upstream;
    proxy_pass $upstream$1$is_args$args; #We rebuild our request URL

You should also have a script before starting Nginx which finds the DNS server and replaces it in the configuration file.

export DOMAIN_DNS=$(cat /etc/resolv.conf |grep -i '^nameserver'|head -n1|cut -d ' ' -f2)
sed -i 's|DOMAIN_DNS|'$DOMAIN_DNS'|g' /etc/nginx/nginx.conf

By doing this, we’ll get the correct DNS resolver everytime we start Nginx.

Why does this work?

Simple. When you use a variable in the proxy_pass, Nginx resolves it dynamically, with a default cache time of 5 minutes. This can be changed passing valid=5s to the resolver setup.

resolver DOMAIN_DNS valid=5s;