Cómo evitar los 10 errores más comunes de configuración de NGINX

NGINX | 22 de febrero de 2022

Cuando ayudamos a usuarios de NGINX que tienen problemas, a menudo vemos los mismos errores de configuración que ya hemos encontrado una y otra vez en las configuraciones de otros usuarios, ¡a veces incluso en configuraciones escritas por otros ingenieros de NGINX! En este blog analizamos 10 de los errores más comunes, explicamos qué está mal y cómo solucionarlo.

  1. No hay suficientes descriptores de archivo por proceso de trabajo
  2. La directiva error_log off directive
  3. No habilitar conexiones persistentes con los servidores ascendentes
  4. Olvidar cómo funciona la herencia de directivas
  5. La directiva «proxy_buffering off»
  6. Uso incorrecto de la directiva «if»
  7. Comprobaciones de estado excesivas
  8. Acceso no seguro a las métricas
  9. Usar ip_hash cuando todo el tráfico procede del mismo bloque CIDR /24
  10. No aprovechar los grupos de servidores upstream

Error 1: No hay suficientes descriptores de archivo por proceso de trabajo

La directiva worker_connections establece el número máximo de conexiones simultáneas que puede mantener abiertas un proceso de trabajo de NGINX (el valor predeterminado es 512). Todos los tipos de conexiones (por ejemplo, las conexiones con servidores proxy) cuentan para este máximo, no solo las conexiones de clientes. Sin embargo, es importante tener en cuenta que existe otro límite para el número de conexiones simultáneas por proceso de trabajo: el límite del sistema operativo relativo al número máximo de descriptores de archivo (FD) asignados a cada proceso. En las distribuciones UNIX modernas, el límite predeterminado es 1024.

Salvo para las implementaciones de NGINX más pequeñas, un límite de 512 conexiones por proceso de trabajo probablemente sea demasiado bajo. De hecho, el archivo nginx.conf predeterminado que distribuimos con los binarios de NGINX Open Source y NGINX Plus aumenta este límite a 1024.

Un error de configuración habitual consiste en no aumentar el límite de descriptores de archivo hasta al menos el doble del valor de worker_connections. Para solucionarlo, establezca dicho valor mediante la directiva worker_rlimit_nofile en el contexto de configuración principal.

Este es el motivo por el que se necesitan más descriptores de archivo (FD): cada conexión de un proceso de trabajo de NGINX a un cliente o servidor ascendente consume un FD. Cuando NGINX actúa como servidor web, utiliza un FD para la conexión con el cliente y otro por cada archivo servido, lo que supone un mínimo de dos FD por cliente (aunque la mayoría de las páginas web se componen de muchos archivos). Cuando actúa como servidor proxy, NGINX utiliza un FD para la conexión con el cliente y otro para la conexión con el servidor ascendente, además de un posible tercer FD para el archivo utilizado para almacenar temporalmente la respuesta del servidor. Como servidor de caché, NGINX se comporta como un servidor web para las respuestas almacenadas en caché y como un servidor proxy si la caché está vacía o ha caducado.

NGINX también utiliza un descriptor de archivo (FD) por cada archivo de registro y un par de ellos para comunicarse con el proceso maestro, pero estas cifras suelen ser pequeñas en comparación con el número de descriptores de archivo utilizados para las conexiones y los archivos.

UNIX ofrece varias formas de establecer el número de descriptores de archivo (FD) por proceso:

  • El comando ulimit si inicia NGINX desde un shell
  • Las variables del script init o del manifiesto del servicio systemd si inicia NGINX como servicio
  • El archivo /etc/security/limits.conf file

Sin embargo, el método que debe utilizar depende de cómo inicie NGINX, mientras que «worker_rlimit_nofile» funciona independientemente de cómo inicie NGINX.

También existe un límite para todo el sistema en cuanto al número de descriptores de archivo, que puede configurar mediante el comando sysctl fs.file-max del sistema operativo. Suele ser lo suficientemente alto, pero conviene comprobar que el número máximo de descriptores de archivo que podrían utilizar todos los procesos de trabajo de NGINX (worker_rlimit_nofile * worker_processes) sea considerablemente inferior a fs.file‑max. Si, por algún motivo, NGINX utiliza todos los descriptores de archivo disponibles (por ejemplo, durante un ataque DoS), ni siquiera será posible iniciar sesión en la máquina para solucionar el problema.

Error 2: La directiva «error_log off»

El error habitual consiste en pensar que la directiva error_log off desactiva el registro. En realidad, a diferencia de la directiva access_log, error_log no admite el parámetro off. Si incluye la directiva error_log off en la configuración, NGINX crea un archivo de registro de errores llamado off en el directorio predeterminado de los archivos de configuración de NGINX (normalmente, /etc/nginx).

No recomendamos desactivar el registro de errores, ya que constituye una fuente de información esencial para depurar cualquier problema con NGINX. Sin embargo, si el almacenamiento es tan limitado que los datos registrados podrían llegar a agotar el espacio disponible en disco, puede tener sentido desactivarlo. Incluya esta directiva en el contexto de configuración principal:

error_log /dev/null emerg;

Ten en cuenta que esta directiva no se aplica hasta que NGINX lee y valida la configuración. Por tanto, cada vez que NGINX se inicia o se vuelve a cargar la configuración, puede escribir en la ubicación predeterminada del registro de errores (normalmente /var/log/nginx/error.log) hasta que se valide la configuración. Para cambiar el directorio del registro, incluye el parámetro -e <error_log_location> en el comando nginx.

Error 3: No habilitar las conexiones persistentes con los servidores ascendentes

De forma predeterminada, NGINX abre una nueva conexión con un servidor ascendente (backend) por cada nueva solicitud entrante. Esto es seguro, pero ineficiente, ya que NGINX y el servidor deben intercambiar tres paquetes para establecer una conexión y tres o cuatro para cerrarla.

Con volúmenes de tráfico elevados, abrir una nueva conexión para cada solicitud puede agotar los recursos del sistema e impedir por completo que se abran conexiones. El motivo es el siguiente: para cada conexión, la tupla de cuatro elementos formada por la dirección de origen, el puerto de origen, la dirección de destino y el puerto de destino debe ser única. En las conexiones de NGINX a un servidor ascendente, tres de los elementos (el primero, el tercero y el cuarto) son fijos, por lo que solo queda el puerto de origen como variable. Cuando se cierra una conexión, el socket de Linux permanece en el estado TIME‑WAIT durante dos minutos, lo que, con volúmenes de tráfico elevados, aumenta la posibilidad de agotar el conjunto de puertos de origen disponibles. Si esto ocurre, NGINX no puede abrir nuevas conexiones con los servidores ascendentes.

La solución consiste en habilitar las conexiones persistentes entre NGINX y los servidores ascendentes: en lugar de cerrarse cuando finaliza una solicitud, la conexión permanece abierta para poder utilizarse en solicitudes posteriores. Esto reduce la posibilidad de agotar los puertos de origen y, además, mejora el rendimiento.

Para habilitar las conexiones persistentes:

  • Incluya la directiva keepalive en cada bloque upstream{} para establecer el número de conexiones keepalive inactivas con los servidores upstream que se conservan en la caché de cada proceso de trabajo. Tenga en cuenta que la directiva keepalive no limita el número total de conexiones con servidores upstream que puede abrir un proceso de trabajo de NGINX; esta es una confusión habitual. Por tanto, el parámetro de keepalive no tiene que ser tan alto como podría pensar. Recomendamos establecer el parámetro en el doble del número de servidores incluidos en el bloque upstream{}. Este valor es lo suficientemente alto como para que NGINX mantenga conexiones keepalive con todos los servidores, pero lo bastante bajo como para que los servidores upstream también puedan procesar nuevas conexiones entrantes. Tenga en cuenta también que, cuando especifique un algoritmo de balanceo de carga en el bloque upstream{} —mediante la directiva hash, ip_hash, least_conn, least_time o random—, esta debe aparecer antes que la directiva keepalive. Esta es una de las pocas excepciones a la regla general de que el orden de las directivas en la configuración de NGINX no importa.
  • En el bloque location{} que reenvía solicitudes a un grupo de servidores upstream, incluya las siguientes directivas junto con la directiva proxy_pass:
proxy_http_version 1.1;
proxy_set_header   "Connection" "";
  • De forma predeterminada, NGINX utiliza HTTP/1.0 para las conexiones con los servidores ascendentes y, por tanto, añade la cabecera Connection: close a las solicitudes que reenvía a los servidores. Como resultado, cada conexión se cierra cuando finaliza la solicitud, a pesar de que la directiva keepalive esté presente en el bloque upstream{}. La directiva proxy_http_version indica a NGINX que utilice HTTP/1.1 en su lugar, y la directiva proxy_set_header elimina el valor close de la cabecera Connection.

Error 4: Olvidar cómo funciona la herencia de directivas

Las directivas de NGINX se heredan hacia abajo, o «de fuera hacia dentro»: un contexto secundario —anidado dentro de otro contexto (su contexto principal)— hereda la configuración de las directivas incluidas en el nivel principal. Por ejemplo, todos los bloques server{} y location{} del contexto http{} heredan el valor de las directivas incluidas en el nivel http, y una directiva de un bloque server{} se hereda en todos los bloques location{} secundarios que contiene. Sin embargo, cuando se incluye la misma directiva tanto en un contexto principal como en su contexto secundario, los valores no se suman, sino que el valor del contexto secundario sustituye al del contexto principal.

El error consiste en olvidar esta «regla de sobrescritura» para las directivas de matriz, que no solo pueden incluirse en varios contextos, sino también varias veces dentro de un mismo contexto. Algunos ejemplos son proxy_set_header y add_header; el hecho de que la segunda contenga «add» en su nombre hace que resulte especialmente fácil olvidar la regla de sobrescritura.

Podemos ilustrar cómo funciona la herencia con este ejemplo de add_header:

http {    
    add_header X-HTTP-LEVEL-HEADER 1;
    add_header X-ANOTHER-HTTP-LEVEL-HEADER 1;

    server {
        listen 8080;
        location / {
            return 200 "OK";
        } 
    }

    server {
        listen 8081;
        add_header X-SERVER-LEVEL-HEADER 1;

        location / {
            return 200 "OK";
        }

        location /test {
            add_header X-LOCATION-LEVEL-HEADER 1;
            return 200 "OK";
        }

        location /correct {
            add_header X-HTTP-LEVEL-HEADER 1;
            add_header X-ANOTHER-HTTP-LEVEL-HEADER 1;

            add_header X-SERVER-LEVEL-HEADER 1;
            add_header X-LOCATION-LEVEL-HEADER 1;
            return 200 "OK";
        } 
    }
}

Para el servidor que escucha en el puerto 8080, no hay ninguna directiva add_header ni en el bloque server{} ni en el bloque location{}. Por tanto, la herencia es sencilla y vemos las dos cabeceras definidas en el contexto http{}:

% curl -i localhost:8080
HTTP/1.1 200 OK
Server: nginx/1.21.5
Date: Mon, 21 Feb 2022 10:12:15 GMT
Content-Type: text/plain
Content-Length: 2
Connection: keep-alive
X-HTTP-LEVEL-HEADER: 1 X-ANOTHER-HTTP-LEVEL-HEADER: 1
OK

Para el servidor que escucha en el puerto 8081, hay una directiva add_header en el bloque server{}, pero no en su bloque secundario location / . La cabecera definida en el bloque server{} sustituye a las dos cabeceras definidas en el contexto http{}:

% curl -i localhost:8081
HTTP/1.1 200 OK
Server: nginx/1.21.5
Date: Mon, 21 Feb 2022 10:12:20 GMT
Content-Type: text/plain
Content-Length: 2
Connection: keep-alive
X-SERVER-LEVEL-HEADER: 1
OK

En el bloque secundario location /test, hay una directiva add_header que sobrescribe tanto la cabecera de su bloque principal server{} como las dos cabeceras del contexto http{}:

% curl -i localhost:8081/test
HTTP/1.1 200 OK
Server: nginx/1.21.5
Date: Mon, 21 Feb 2022 10:12:25 GMT
Content-Type: text/plain
Content-Length: 2
Connection: keep-alive
X-LOCATION-LEVEL-HEADER: 1
OK

Si queremos que un bloque location{} conserve las cabeceras definidas en sus contextos superiores junto con las definidas localmente, debemos volver a definir las cabeceras superiores dentro del bloque location{}. Eso es lo que hemos hecho en el bloque location /correct:

% curl -i localhost:8081/correct
HTTP/1.1 200 OK
Server: nginx/1.21.5
Date: Mon, 21 Feb 2022 10:12:30 GMT
Content-Type: text/plain
Content-Length: 2
Connection: keep-alive
X-HTTP-LEVEL-HEADER: 1 X-ANOTHER-HTTP-LEVEL-HEADER: 1 X-SERVER-LEVEL-HEADER: 1 X-LOCATION-LEVEL-HEADER: 1
OK

Error 5: La directiva proxy_buffering off Directive

El almacenamiento en búfer del proxy está activado de forma predeterminada en NGINX (la directiva proxy_buffering está configurada como on). Esto significa que NGINX almacena la respuesta de un servidor en búferes internos a medida que la recibe y no empieza a enviar datos al cliente hasta que la respuesta completa se ha almacenado en el búfer. El almacenamiento en búfer ayuda a optimizar el rendimiento con clientes lentos: como NGINX almacena la respuesta durante el tiempo que el cliente necesite para recuperarla por completo, el servidor proxy puede devolver su respuesta lo antes posible y volver a estar disponible para atender otras solicitudes.

Cuando el almacenamiento en búfer del proxy está deshabilitado, NGINX almacena únicamente la primera parte de la respuesta de un servidor antes de empezar a enviarla al cliente, en un búfer cuyo tamaño predeterminado es de una página de memoria (4 KB u 8 KB, según el sistema operativo). Por lo general, este espacio es suficiente para la cabecera de la respuesta. A continuación, NGINX envía la respuesta al cliente de forma síncrona a medida que la recibe, lo que obliga al servidor a permanecer inactivo mientras espera a que NGINX pueda aceptar el siguiente segmento de la respuesta.

Por eso nos sorprende la frecuencia con la que vemos proxy_buffering off en las configuraciones. Quizá se pretenda reducir la latencia que experimentan los clientes, pero el efecto es insignificante y los efectos secundarios son numerosos: con el almacenamiento en búfer del proxy desactivado, la limitación de velocidad y el almacenamiento en caché no funcionan aunque estén configurados, el rendimiento se resiente, etc.

Solo hay un reducido número de casos de uso en los que podría tener sentido deshabilitar el almacenamiento en búfer del proxy (como el sondeo largo), por lo que desaconsejamos encarecidamente cambiar la configuración predeterminada. Para obtener más información, consulte la Guía de administración de NGINX Plus.

Error 6: Uso incorrecto de la directiva «if»

La directiva if es difícil de usar, especialmente en los bloques location{}. A menudo no hace lo que se espera e incluso puede provocar fallos de segmentación. De hecho, es tan problemática que en la wiki de NGINX hay un artículo titulado «If is Evil», al que remitimos para consultar un análisis detallado de los problemas y cómo evitarlos.

En general, las únicas directivas que siempre se pueden usar de forma segura dentro de un bloque if{} son return y rewrite. En el siguiente ejemplo se usa if para detectar solicitudes que incluyen la cabecera X‑Test (aunque puede tratarse de cualquier condición que se quiera comprobar). NGINX devuelve el error 430 (Request Header Fields Too Large), lo intercepta en la ubicación con nombre @error_430 y redirige la solicitud mediante proxy al grupo de servidores ascendentes denominado b.

location / {    
    error_page 430 = @error_430;
    if ($http_x_test) {
        return 430; 
    }

    proxy_pass http://a;
}

location @error_430 {
    proxy_pass b;
}

Para este y muchos otros usos de if, a menudo es posible evitar por completo la directiva. En el siguiente ejemplo, cuando la solicitud incluye la cabecera X‑Test, el bloque map{} asigna el valor b a la variable $upstream_name y la solicitud se reenvía mediante proxy al grupo de servidores upstream con ese nombre.

map $http_x_test $upstream_name {    
    default "b";
    ""      "a";
}

# ...

location / {
    proxy_pass http://$upstream_name;
}

Error 7: comprobaciones de estado excesivas

Es bastante habitual configurar varios servidores virtuales para que actúen como proxy de las solicitudes dirigidas al mismo grupo de servidores ascendentes (es decir, incluir la misma directiva proxy_pass en varios bloques server{}). El error en esta situación consiste en incluir una directiva health_check en cada bloque server{}. Esto solo aumenta la carga de los servidores ascendentes sin aportar información adicional.

Aunque resulte obvio, la solución consiste en definir una sola comprobación de estado por cada bloque upstream{}. Aquí definimos la comprobación de estado del grupo de servidores ascendentes denominado b en una ubicación con nombre específica, con los tiempos de espera y los ajustes de cabeceras adecuados.

location / {    
    proxy_set_header Host $host;
    proxy_set_header "Connection" "";
    proxy_http_version 1.1;
    proxy_pass http://b;
}

location @health_check {
    health_check;
    proxy_connect_timeout 2s;
    proxy_read_timeout 3s;
    proxy_set_header Host example.com;
    proxy_pass http://b;
}

En configuraciones complejas, la gestión puede simplificarse aún más agrupando todas las ubicaciones de comprobación de estado en un único servidor virtual junto con la API y el panel de NGINX Plus, como en este ejemplo.

server {	
        listen 8080;
 
	location / {
	    # …
 	}
 
	location @health_check_b {
	    health_check;
	    proxy_connect_timeout 2s;
	    proxy_read_timeout 3s;
	    proxy_set_header Host example.com;
	    proxy_pass http://b;
	}
 
	location @health_check_c {
	    health_check;
	    proxy_connect_timeout 2s;
	    proxy_read_timeout 3s;
	    proxy_set_header Host api.example.com;
	    proxy_pass http://c;
	}
 
	location /api {
	    api write=on;
	    # directives limiting access to the API (see 'Mistake 8' below)
	}
 
	location = /dashboard.html {
	    root   /usr/share/nginx/html;
	}
}

Para obtener más información sobre las comprobaciones de estado de servidores HTTP, TCP, UDP y gRPC, consulte la Guía de administración de NGINX Plus.

Error 8: acceso no seguro a las métricas

Las métricas básicas sobre el funcionamiento de NGINX están disponibles en el módulo Stub Status. En el caso de NGINX Plus, también puede recopilar un conjunto de métricas mucho más amplio mediante la API de NGINX Plus. Para habilitar la recopilación de métricas, incluya la directiva stub_status o api, respectivamente, en un bloque server{} o location{}, que se convierte en la URL a la que deberá acceder para consultar las métricas. (En el caso de la API de NGINX Plus, también debe configurar zonas de memoria compartida para las entidades de NGINX —servidores virtuales, grupos de servidores ascendentes, cachés, etc.— cuyas métricas quiera recopilar; consulte las instrucciones de la Guía de administración de NGINX Plus.)

Algunas de las métricas contienen información confidencial que puede utilizarse para atacar su sitio web o las aplicaciones para las que NGINX actúa como proxy, y un error que observamos a veces en las configuraciones de los usuarios es no restringir el acceso a la URL correspondiente. A continuación, veremos algunas formas de proteger las métricas. En los primeros ejemplos utilizaremos stub_status.

Con la siguiente configuración, cualquier persona en Internet puede acceder a las métricas en http://example.com/basic_status.

server {    
    listen 80;
    server_name example.com;

    location = /basic_status {
        stub_status;
    }
}

Protege las métricas con autenticación básica HTTP

Para proteger las métricas con contraseña mediante autenticación básica HTTP, incluye las directivas auth_basic y auth_basic_user_file. El archivo (en este caso, .htpasswd) contiene los nombres de usuario y las contraseñas de los clientes que pueden iniciar sesión para consultar las métricas:

server {    
    listen 80;
    server_name example.com;

    location = /basic_status {
        auth_basic “closed site”;
        auth_basic_user_file conf.d/.htpasswd;
        stub_status;
    }
}

Proteja las métricas con las directivas allow y deny Directives

Si no quiere que los usuarios autorizados tengan que iniciar sesión y conoce las direcciones IP desde las que accederán a las métricas, otra opción es la directiva allow. Puede especificar direcciones IPv4 e IPv6 individuales e intervalos CIDR. La directiva deny all impide el acceso desde cualquier otra dirección.

server {    
    listen 80;
    server_name example.com;

    location = /basic_status {
        allow 192.168.1.0/24;
        allow 10.1.1.0/16;
        allow 2001:0db8::/32;
        allow 96.1.2.23/32;
        deny  all;
        stub_status;
    }
}

Combinar los dos métodos

¿Y si queremos combinar ambos métodos? Podemos permitir que los clientes accedan a las métricas desde determinadas direcciones sin contraseña y, al mismo tiempo, exigir que inicien sesión los clientes que se conecten desde otras direcciones. Para ello, usamos la directiva satisfy any. Esta indica a NGINX que permita el acceso a los clientes que inicien sesión con credenciales de autenticación básica HTTP o que utilicen una dirección IP previamente autorizada. Para mayor seguridad, puede establecer satisfy en all para exigir que incluso quienes se conecten desde determinadas direcciones inicien sesión.

server {    
    listen 80;
    server_name monitor.example.com;

    location = /basic_status {
        satisfy any;

        auth_basic “closed site”;
        auth_basic_user_file conf.d/.htpasswd;
        allow 192.168.1.0/24;
        allow 10.1.1.0/16;
        allow 2001:0db8::/32;
        allow 96.1.2.23/32;
        deny  all;
        stub_status;
    }
}

Con NGINX Plus, se utilizan las mismas técnicas para limitar el acceso al endpoint de la API de NGINX Plus (http://monitor.example.com:8080/api/ en el siguiente ejemplo), así como al panel de monitorización de la actividad en tiempo real disponible en http://monitor.example.com/dashboard.html.

Esta configuración permite el acceso sin contraseña únicamente a los clientes procedentes de la red 96.1.2.23/32 o de localhost. Dado que las directivas se definen en el nivel server{}, las mismas restricciones se aplican tanto a la API como al panel de control. Como nota adicional, el parámetro write=on de api permite que estos clientes también utilicen la API para realizar cambios en la configuración.

Para obtener más información sobre cómo configurar la API y el panel de control, consulte la Guía de administración de NGINX Plus.

server {    
    listen 8080;
    server_name monitor.example.com;
 
    satisfy any;
    auth_basic “closed site”;
    auth_basic_user_file conf.d/.htpasswd;
    allow 127.0.0.1/32;
    allow 96.1.2.23/32;
    deny  all;

    location = /api/ {    
        api write=on;
    }

    location = /dashboard.html {
        root /usr/share/nginx/html;
    }
}

Error 9: Usar ip_hash cuando todo el tráfico procede del mismo bloque CIDR /24

El algoritmo ip_hash equilibra la carga del tráfico entre los servidores de un bloque upstream{} basándose en un hash de la dirección IP del cliente. La clave de hash son los tres primeros octetos de una dirección IPv4 o la dirección IPv6 completa. Este método establece la persistencia de sesión, lo que significa que las solicitudes de un cliente siempre se envían al mismo servidor, salvo cuando este no está disponible.

Supongamos que hemos implementado NGINX como proxy inverso en una red privada virtual configurada para ofrecer alta disponibilidad. Colocamos varios cortafuegos, routers, balanceadores de carga de capa 4 y puertas de enlace delante de NGINX para aceptar tráfico de distintas fuentes (la red interna, las redes de socios, Internet, etc.) y enviarlo a NGINX para que lo redirija mediante proxy inverso a los servidores upstream. Esta es la configuración inicial de NGINX:

http {
    upstream {
        ip_hash;
        server 10.10.20.105:8080;
        server 10.10.20.106:8080;
        server 10.10.20.108:8080;
    }
 
    server {# …}
}

Pero resulta que hay un problema: todos los dispositivos de «interceptación» están en la misma red 10.10.0.0/24, por lo que, para NGINX, parece que todo el tráfico procede de direcciones de ese rango CIDR. Recuerde que el algoritmo ip_hash calcula el hash de los tres primeros octetos de una dirección IPv4. En nuestro despliegue, los tres primeros octetos son los mismos —10.10.0— para todos los clientes, por lo que el hash es idéntico para todos ellos y no hay ningún criterio para distribuir el tráfico entre distintos servidores.

La solución consiste en utilizar el algoritmo hash con la variable $binary_remote_addr como clave hash. Esta variable captura la dirección completa del cliente y la convierte en una representación binaria de 4 bytes para una dirección IPv4 y de 16 bytes para una dirección IPv6. De este modo, el hash es diferente para cada dispositivo de interceptación y el balanceo de carga funciona según lo previsto.

También incluimos el parámetro «consistent» para utilizar el método de hash ketama en lugar del predeterminado. Esto reduce considerablemente el número de claves que se reasignan a otro servidor ascendente cuando cambia el conjunto de servidores, lo que se traduce en una mayor tasa de aciertos de caché en los servidores de caché.

http {    
        upstream {
        hash $binary_remote_addr consistent;
        server 10.10.20.105:8080;
        server 10.10.20.106:8080;
        server 10.10.20.108:8080;
    }

    server {# …}
}

Error 10: No aprovechar los grupos de servidores upstream

Supongamos que utiliza NGINX para uno de los casos de uso más sencillos: como proxy inverso para una única aplicación backend basada en NodeJS que escucha en el puerto 3000. Una configuración habitual podría ser la siguiente:

http {
    server {
        listen 80;
        server_name example.com;

        location / {
            proxy_set_header Host $host;
            proxy_pass http://localhost:3000/;
        }
    }
}

Sencillo, ¿verdad? La directiva proxy_pass indica a NGINX dónde enviar las solicitudes de los clientes. NGINX solo tiene que resolver el nombre de host en una dirección IPv4 o IPv6. Una vez establecida la conexión, NGINX reenvía las solicitudes a ese servidor.

El error aquí es suponer que, como solo hay un servidor —y, por tanto, no hay motivo para configurar el balanceo de carga—, no tiene sentido crear un bloque upstream{}. En realidad, un bloque upstream{} habilita varias funciones que mejoran el rendimiento, como muestra esta configuración:

http {
    upstream node_backend {
        zone upstreams 64K;
        server 127.0.0.1:3000 max_fails=1 fail_timeout=2s;
        keepalive 2;
    }

    server {
        listen 80;
        server_name example.com;

        location / {
            proxy_set_header Host $host;
            proxy_pass http://node_backend/;
            proxy_next_upstream error timeout http_500;

        }
    }
}

La directiva zone establece una zona de memoria compartida en la que todos los procesos de trabajo de NGINX del host pueden acceder a la información de configuración y estado de los servidores ascendentes. Varios grupos de servidores ascendentes pueden compartir la zona. Con NGINX Plus, la zona también permite usar la API de NGINX Plus para cambiar los servidores de un grupo de servidores ascendentes y la configuración de cada servidor sin reiniciar NGINX. Para obtener más información, consulte la Guía de administración de NGINX Plus.

La directiva server tiene varios parámetros que puede utilizar para ajustar el comportamiento del servidor. En este ejemplo, hemos cambiado las condiciones que utiliza NGINX para determinar que un servidor no está en buen estado y, por tanto, no puede aceptar solicitudes. En este caso, considera que un servidor no está en buen estado si se produce un solo fallo en un intento de comunicación durante cada período de 2 segundos (en lugar del valor predeterminado de un fallo durante un período de 10 segundos).

Combinamos esta configuración con la directiva proxy_next_upstream para definir qué considera NGINX un intento de comunicación fallido, en cuyo caso pasa las solicitudes al siguiente servidor del grupo de servidores ascendentes. A las condiciones predeterminadas de error y tiempo de espera añadimos http_500 para que NGINX considere que un código HTTP 500 (Error interno del servidor) procedente de un servidor ascendente representa un intento fallido.

La directiva keepalive establece el número de conexiones persistentes inactivas con servidores ascendentes que se conservan en la caché de cada proceso de trabajo. Ya hemos explicado sus ventajas en Error 3: No habilitar las conexiones persistentes con servidores ascendentes.

Con NGINX Plus puede configurar funciones adicionales con grupos de servidores upstream:

  • Como hemos mencionado anteriormente, NGINX Open Source resuelve los nombres de host de los servidores en direcciones IP una sola vez, durante el arranque. El parámetro resolve de la directiva server permite que NGINX Plus supervise los cambios en las direcciones IP correspondientes al nombre de dominio de un servidor ascendente y modifique automáticamente la configuración del grupo de servidores ascendentes sin necesidad de reiniciar. El parámetro service también permite que NGINX Plus utilice registros DNS SRV, que incluyen información sobre números de puerto, pesos y prioridades. Esto es fundamental en entornos de microservicios, donde los números de puerto de los servicios suelen asignarse dinámicamente. Para obtener más información sobre la resolución de direcciones de servidores, consulte Uso de DNS para la detección de servicios con NGINX y NGINX Plus en nuestro blog.
  • El parámetro slow_start de la directiva server permite que NGINX Plus aumente gradualmente el volumen de solicitudes que envía a un servidor que acaba de considerarse en buen estado y disponible para aceptar solicitudes. Esto evita una avalancha repentina de solicitudes que podría sobrecargar el servidor y provocar que vuelva a fallar.
  • La directiva queue permite a NGINX Plus poner las solicitudes en cola cuando no es posible seleccionar un servidor ascendente para atenderlas, en lugar de devolver inmediatamente un error al cliente.

Recursos

Para probar NGINX Plus, empieza hoy mismo tu prueba gratuita de 30 días o contacta con nosotros para hablar sobre tus casos de uso.


Compartir
Etiquetas: F5 NGINX, 2021, Tech

Sobre el autor

Timo Stark
Timo StarkIngeniero de gestión de productos

Más artículos de Timo Stark

Artículos relacionados del blog

Únete a F5 NGINX en AppWorld 2024
NGINX | 04/01/2024

Únete a F5 NGINX en AppWorld 2024

Descubre las numerosas razones para asistir al evento insignia de F5, que incluirá un emocionante anuncio sobre la cartera de productos NGINX.

Rotación de certificados SSL/TLS sin reinicios en NGINX Open Source
NGINX | 26/09/2023

Rotación de certificados SSL/TLS sin reinicios en NGINX Open Source

La función de diccionario compartido permite configurar NGINX sin necesidad de reiniciarlo al renovar los certificados SSL/TLS.

Exposición de APIs en Kubernetes
NGINX | 10/03/2022

Exposición de APIs en Kubernetes

La unidad 2 de Microservices March 2022 se centra en cómo exponer tus API en Kubernetes. Aquí tienes enlaces a los recursos que necesitas: la retransmisión en directo del 14 de marzo, artículos de blog y otros recursos de preparación, y el laboratorio práctico «Protege las API de Kubernetes mediante la limitación de solicitudes».

NGINX Sprint 2.0: visión clara, código renovado y nuevos compromisos con el código abierto
NGINX | 23/08/2021

NGINX Sprint 2.0: visión clara, código renovado y nuevos compromisos con el código abierto

Hoy, en NGINX Sprint 2.0, anunciamos cómo respaldaremos nuestra visión del futuro de las aplicaciones modernas con una mayor presencia en la comunidad de código abierto, incluida la participación en el proyecto comunitario Kubernetes, nuevos proyectos de software de código abierto y la arquitectura de referencia para aplicaciones modernas.

Presentamos NGINX Plus R22
NGINX | 09/06/2020

Presentamos NGINX Plus R22

NGINX Plus R22 incorpora nuevas funcionalidades, como la compatibilidad con OCSP para verificar la revocación de certificados en TLS mutuo, el uso de varios proveedores de identidad OIDC en una configuración, el seguimiento en tiempo real de la limitación de solicitudes y conexiones en el panel de NGINX Plus y mejoras en NGINX JavaScript.

Presentamos NGINX Plus R17
NGINX | 11/12/2018

Presentamos NGINX Plus R17

NGINX Plus R17 incorpora compatibilidad con la limitación de velocidad en dos fases y con TLS 1.3, la versión más reciente del protocolo Transport Layer Security. La configuración de OpenID Connect es más sencilla y NGINX ModSecurity WAF es el doble de rápido que antes. También se ha actualizado el módulo JavaScript de NGINX.