35

Is it possible to set resolver address in nginx proxy configuration from /etc/resolv.conf?

It can be useful for example in docker or in virtualenvironment.

Nikolai Golub
  • 480
  • 2
  • 5
  • 10

5 Answers5

22

Unfortunately there's no easy way to do this because nginx use it's own resolver implementation. The two solutions I see are :

1) You generate the resolver list from a script and include it, e.g. :

echo resolver $(awk 'BEGIN{ORS=" "} $1=="nameserver" {print $2}' /etc/resolv.conf) ";" > /etc/nginx/resolvers.conf

http {

    include resolvers.conf;

}

2) You recompile nginx with a third party module like the (very) experimental perl module and write a variable handler :

http {

    perl_modules perl/lib;
    perl_set $resolvers '

        sub {
            return system("awk BEGIN{ORS=\" \"} /nameserver/{print \$2}" /etc/resolv.conf");
        };

    resolver "$resolvers";
}

Now, if you are a hell of a C coder (prepare your eyes for some blood), you can still write an alternative patch or module to make it work this way.

Marko Kohtala
  • 315
  • 1
  • 7
Xavier Lucas
  • 13,095
  • 2
  • 44
  • 50
14

If you're using the Openresty version of nginx then you can use their special local argument to the resolver directive which when set to local=on, means the standard path of /etc/resolv.conf will be used by the resolver (for more details see Openresty resolver docs):

resolver local=on;
Pierz
  • 623
  • 8
  • 9
  • Thank you! This indeed works with OpenResty. For the reference this is the container version I tried it with: `openresty/openresty:1.15.8.2-6-buster-fat`. I really like this solution since it is environment agnostic and does not require any fragile scripting tricks. – Andrei Sinitson Feb 19 '20 at 06:12
10

For Kubernetes, you can simply add kube-dns as resolver.
The FQDN of the resolver is based on the namespace, by default kube-system.
You might have to change the FQDN to accommodate your configuration.

location / {
   ...
   resolver kube-dns.kube-system.svc.cluster.local;
   ...
}

You can read more about DNS and services here https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/

Michael
  • 201
  • 2
  • 4
8

For Docker users, solution found here:

Heres a workaround for people using Docker.

export NAMESERVER=`cat /etc/resolv.conf | grep "nameserver" | awk '{print $2}' | tr '\n' ' '`

What this does is take all the nameserver entries from /etc/resolv.conf and print them in a line, so you can use them with nginx's resolver directive. Your Dockerfile will need to have a custom script for the entrypoint that generates the config file and then starts nginx. Lets say you have a file called nginx.conf.template that looks something like:

...snip...
http {
  server {

    resolver $NAMESERVER valid=10s;

    ...snip....  
    }
  }
}

Your startup script can then use the envsubst program to generate an nginx.conf and then start nginx. eg:

#!/bin/bash
if [ "$NAMESERVER" == "" ]; then
    export NAMESERVER=`cat /etc/resolv.conf | grep "nameserver" | awk '{print $2}' | tr '\n' ' '`
fi

echo "Nameserver is: $NAMESERVER"

echo "Copying nginx config"
envsubst '$NAMESERVER' < /nginx.conf.template > /nginx.conf

echo "Using nginx config:"
cat /nginx.conf

echo "Starting nginx"
nginx -c /nginx.conf -g "daemon off;"

NOTE that in docker this tend to result in the same file, as by default the docker embedded DNS server is 127.0.0.11, see this answer to Docker Network Nginx Resolver.

Andrew Schulman
  • 8,811
  • 21
  • 32
  • 47
FelikZ
  • 345
  • 1
  • 4
  • 12
  • 6
    Awk, learn it, it's a fantastic tool for text munging: `export NAMESERVER=$(awk '/^nameserver/{print $2}' /etc/resolv.conf)`. No need for `cat`, `grep` or `tr` in there. – j0057 Jul 03 '18 at 08:16
  • this doesn't work on Kubernetes though. – Kim Aug 07 '19 at 20:24
  • I used `NGX_DNS_RESOLVER=$(awk '/nameserver/{a=(a?a" "$2:$2)} END{print a}' /etc/resolv.conf 2> /dev/null)` – samm Feb 26 '21 at 06:17
  • 1
    For docker users, I recommend putting `exec ` at the front of the bottom line. It makes nginx PID 1, so that commands like `docker kill --signal=HUP ` (reload config) work. – mikedep333 Oct 31 '22 at 18:07
2

If your system uses resolvconf (as many virtual machines do, but unfortunately Docker does not, see man 8 resolvconf), you might create the nginx resolvers.conf (as in the other answer) in /etc/resolvconf/update-libc.d/nginx. This behaves nicely even in the rare case of dynamic change of resolvers.

#!/bin/sh
conf="resolver $(/usr/bin/awk 'BEGIN{ORS=" "} $1=="nameserver" {print $2}' /etc/resolv.conf);"
[ "$conf" = "resolver ;" ] && exit 0
confpath=/etc/nginx/conf.d/resolvers.conf
if [ ! -e $confpath ] || [ "$conf" != "$(cat $confpath)" ]
then
    echo "$conf" > $confpath
    service nginx reload >/dev/null
fi
exit 0

Some linux distributions include /etc/nginx/conf.d/*.conf in their default configuration. Reload is usually ignored when service is not running. Notice the script may be run without /usr/bin in PATH, so you may need absolute path to awk.

Marko Kohtala
  • 315
  • 1
  • 7