Forum Discussion

mangoo's avatar
mangoo
Icon for Nimbostratus rankNimbostratus
Nov 01, 2022

does nginx (1.20 or newer) re-resolve DNS for proxy_pass?

Consider this nginx config snippet:

       location ^~ /_example/ {
           proxy_pass https://example.com/_example/;
           proxy_set_header Host my-site;
       }

Assuming "example.com" DNS TTL is set to 60 seconds - will nginx re-resolve DNS after 60 seconds? Or does it only resolve the name on startup? I'm finding different info around the internet:
- it will re-resolve only in the commercial nginx plus
- it will re-resolve only in newer nginx releases; in older ones, one need to make some workarounds
- it will only resolve once on startup and never again

  • I can confirm that resolver not working when i did the same setup like above

    resolver 10.0.0.2 valid=10s;
    
    server {
        location / {
            set $backend_servers backends.example.com;
            proxy_pass http://$backend_servers:8080;
        }
    }

    nginx v1.24.0 and v.1.25.2, both of them do not work. Seems like they going to take care nginx plus version too much and forget to fix this in the open source version.

  • This blog post explains the various methods NGINX and NGINX Plus handles domain resolution - https://www.nginx.com/blog/dns-service-discovery-nginx-plus/. To summarize, you can configure NGINX to resolve hostnames regularly using these methods (credits to original blog post):

    1. Setting the Domain Name in a Variable

    resolver 10.0.0.2 valid=10s;
    
    server {
        location / {
            set $backend_servers backends.example.com;
            proxy_pass http://$backend_servers:8080;
        }
    }

    NGINX re‑resolves the domain name when its TTL expires. You must include the 

    resolver
     directive to explicitly specify the name server (NGINX does not refer to /etc/resolv.conf as in the first two methods). By including the 
    valid
     parameter to the 
    resolver
     directive, you can tell NGINX to ignore the TTL and re‑resolve names at a specified frequency instead. Here we tell NGINX to re‑resolve names every 10 seconds.

    Drawback is that because the upstream group is not used, specify the load‑balancing algorithm or other parameters to the server directive.

    2. (NGINX Plus only) Using DNS A records

    resolver 10.0.0.2 valid=10s;
    
    upstream backends {
        zone backends 64k;
        server backends.example.com:8080 resolve;
    }
    
    server {
        location / {
            proxy_pass http://backends;
        }
    }

    By default, NGINX Plus honors the TTL, re‑resolving names when records expire. To have NGINX Plus instead re‑resolve names at a specified frequency, include the valid parameter to the resolver directive.

    This gives the additional benefit of being able to configure additional settings for upstream servers via the server directive.

    ---

    Do take a look at the blog post to see other methods available, such as via DNS SRV records which supports dynamic port numbers and weightings. Hope that helps.

    • mangoo's avatar
      mangoo
      Icon for Nimbostratus rankNimbostratus

      I've made a set of tests (I use a regular nginx 1.20.1 version, not nginx plus):

      1. According to tcpdump - nginx will periodically re-query the DNS for "example.com" if the following config part is used:

             location ^~ /_example/ {
                 proxy_pass https://example.com/_example/;
                 proxy_set_header Host my-site;
             }

      However, confusingly - even if DNS changed, the value resolved at nginx startup will be still used!

      2. Setting the domain name in the variable - this unfortunately works differently than the "equivalent" without the variable:

      a) without the variable:


             location ^~ /_example/ {
                 proxy_pass https://example.com/_example/;
                 proxy_set_header Host my-site;
             }

      - connection to local-server/_example/image.jpg will be passed to example.com/_example/image.jpg
      - only DNS resolved at startup is used, even though nginx queries DNS for "example.com" from time to time

       

      b) with the variable:

             location ^~ /_example/ {
                 set $backend_server example.com;
                 proxy_pass https://$backend_server/_example/;
                 proxy_set_header Host my-site;
             }

      - connection to local-server/_example/image.jpg will be passed to example.com/_example/ - note the missing "image.jpg" when querying the upstream!
      - DNS changes work

      • Leon_Seng's avatar
        Leon_Seng
        Icon for Employee rankEmployee

        On 1, I don't have knowledge of how the underlying code is written, but barring the periodic DNS requests, NGINX seems to be behaving as intended in terms of resolving the host with new value after restart/config reload.

        On 2, try changing your location block to

        location ^~ /_example/ {
            set $backend_server example.com;
            proxy_pass https://$backend_server/$request_uri;
            proxy_set_header Host my-site;
        }