¿Cómo forzar a nginx a resolver DNS (de un nombre de host dinámico) cada vez que se hace proxy_pass?

52

Estoy usando nginx / 0.7.68, ejecutándome en CentOS, con la siguiente configuración:

server {
    listen       80;
    server_name ***;
    index index.html index.htm index.php default.html default.htm default.php;

    location / {
            root   /***;
            proxy_pass   http://***:8888;
            index  index.html index.htm;
    }
    # where *** is my variables

El proxy_passes un registro DNS cuya IP cambia con frecuencia. Nginx almacena en caché la dirección IP desactualizada, lo que resulta en una solicitud a la dirección IP incorrecta.

¿Cómo puedo evitar que nginx guarde en caché la dirección IP cuando está desactualizada?

xiamx
fuente
mirando a través de la fuente nginx, parece que nginx está codificado para la caché resuelve para su TTL: ¿cuál es el TTL en su dns dinámico?
lunixbochs
TTL en mi ddns es 60, el valor predeterminado de dyndns.com
xiamx
relacionado: serverfault.com/questions/560632/…
nick fox

Respuestas:

8

Es una pregunta intrigante y AFAIK que no va a funcionar bien. Puede intentar usar el módulo ascendente y usar las directivas para la conmutación por error para ver si funciona como un hack.

Edición de 2018: muchas cosas cambiaron. Verifique la respuesta de @ohaal para obtener información real sobre esto.

volcado de memoria
fuente
1
Sorprendentemente, cuando cambié a aguas arriba, todo funcionó como se esperaba. Voy a continuación, marca esto como respuesta correcta
xiamx
1
De acuerdo con la documentación, hay un serverindicador ascendente especial resolveque solo está disponible en la versión comercial (consulte nginx.org/en/docs/http/ngx_http_upstream_module.html#server )
omribahumi
1
@gansbrest ese sitio parece ser algún tipo de sitio spam? Le pediría que elimine su respuesta.
majikman
90

La respuesta aceptada no funcionó para mí en nginx / 1.4.2.

El uso de una variable proxy_passfuerza la re-resolución de los nombres DNS porque NGINX trata las variables de manera diferente a la configuración estática. De la documentación de NGINXproxy_pass :

El valor del parámetro puede contener variables. En este caso, si se especifica una dirección como nombre de dominio, se busca el nombre entre los grupos de servidores descritos y, si no se encuentra, se determina mediante un resolutor.

Por ejemplo:

server {
    ...
    resolver 127.0.0.1;
    set $backend "http://dynamic.example.com:80";
    proxy_pass $backend;
    ...
}

Nota: DEBE estar disponible un configurador (es decir, el servidor de nombres que se utilizará) y configurado para que funcione (y las entradas dentro de un /etc/hostsarchivo no se utilizarán en una búsqueda).

Por defecto, la versión 1.1.9 o versiones posteriores de NGINX caché responde usando el valor TTL de una respuesta y un validparámetro opcional permite que el tiempo de caché se anule:

resolver 127.0.0.1 [::1]:5353 valid=30s;

Antes de la versión 1.1.9, el ajuste del tiempo de almacenamiento en caché no era posible, y nginx siempre almacenaba en caché las respuestas durante 5 minutos. .

ohaal
fuente
¿no forzaría esto una consulta dns en cada solicitud? eso suena como una actuación horrible ...
lucascaro
No, lee la fuente. In such setup ip address of "foo.example.com" will be looked up dynamically and result will be cached for 5 minutes.Lo agregué a la respuesta para mayor claridad.
Ohaal
13
Después de pasar la mayor parte de mi día en esto, en Ubuntu 12.04 con nginx 1.1.19, el setinterior locationno funciona correctamente. Cuidado
omribahumi
Esta solución funcionó conmigo, sin embargo, no pude encontrar una referencia para el TTL de 5 minutos. nginx.org/en/docs/http/ngx_http_core_module.html#resolver By default, nginx caches answers using the TTL value of a response. An optional valid parameter allows overriding it: resolver 127.0.0.1 [::1]:5353 valid=30s;
Montaro
44
Nota: para Docker, su resolución de DNS reside en 127.0.0.11, por lo que para el desarrollo, uso esto:resolver 127.0.0.11 [::1]:5353 valid=15s;
Dalibor Filus
9

Hay información valiosa en el comentario de Gansbrest y la respuesta oficial.

Pero creo que es importante mencionar este artículo oficial de nginx, publicado en 2016, que explica claramente el comportamiento de nginx en este asunto y las posibles soluciones: https://www.nginx.com/blog/dns-service-discovery-nginx-plus / /

De hecho, tenemos que "Establecer el nombre de dominio en una variable" y usar la directiva de resolución .

sin embargo, el uso de una variable cambia el comportamiento de reescritura. Es posible que deba usar la directiva de reescritura, depende de su ubicación y de la configuración de proxy_pass.

PD: habría publicado un comentario pero aún no hay suficientes puntos ...

Jack B.
fuente
1

La respuesta de ohaal nos lleva a la mayoría de nosotros, pero hay un caso en el que el solucionador DNS no vive en 127.0.0.1 (por ejemplo, cuando se encuentra en un entorno contenedorizado especial)

En ese caso, es posible que desee cambiar la configuración de nginx resolver ${DNS_SERVER};. Luego, antes de comenzar nginx, ejecute

export DNS_SERVER=$(cat /etc/resolv.conf |grep -i '^nameserver'|head -n1|cut -d ' ' -f2)
envsubst '${DNS_SERVER} < your_nginx.conf.template > your_nginx.conf
Wonton
fuente
0

He pirateado un script para ver una carpeta conf.d en sentido ascendente en busca de cambios dns y volver a cargar nginx tras la detección. Es un primer paso, y seguramente se puede mejorar (el próximo paso, usaré nginx -T para analizar específicamente las secuencias ascendentes. La misma idea podría usarse para las directivas proxy_pass):

#!/bin/bash

get_upstreams() {
  local files=$@
  grep -hEo '(server\s+)[^:;]+' $files | cut -d' ' -f 2
}

resolve_hosts() {
  local hosts=$@
  for h in $hosts; do dig +short $h; done | sort -u
}

watch_dir=$1

[ -d $watch_dir ] || exit 2

upstreams=$(get_upstreams $watch_dir/*)
ips=$(resolve_hosts $upstreams)
if [ ! "$ips" ]; then
  echo "Found no resolvable hosts in $watch_dir files."
fi

host_hash=$(echo $ips | /usr/bin/sha512sum)

echo $host_hash
echo $ips

while [ -d $watch_dir ]; do
  sleep 30
  upstreams=$(get_upstreams $watch_dir/*)
  ips=$(resolve_hosts $upstreams)
  new_hash=$(echo $ips | /usr/bin/sha512sum)
  if [ "$host_hash" != "$new_hash" ]; then
    echo Detected an upstream address change.  $ips
    echo Reloading nginx
    echo $new_hash
    echo $ips
    /sbin/service nginx reload
    host_hash=$new_hash
  fi
done
mushuweasel
fuente