BLOG | NGINX

Éviter les 10 principales erreurs de configuration de NGINX

NGINX-Partie-de-F5-horiz-black-type-RGB
Vignette de Timo Stark
Timo Stark
Publié le 22 février 2022

Lorsque nous aidons les utilisateurs de NGINX qui rencontrent des problèmes, nous constatons souvent les mêmes erreurs de configuration que nous avons vues à maintes reprises dans les configurations d’autres utilisateurs – parfois même dans des configurations écrites par d’autres ingénieurs NGINX ! Dans ce blog, nous examinons 10 des erreurs les plus courantes, en expliquant ce qui ne va pas et comment y remédier.

  1. Pas assez de descripteurs de fichiers par travailleur
  2. La directive error_log off
  3. Ne pas activer les connexions keepalive aux serveurs en amont
  4. Oublier comment fonctionne l'héritage directif
  5. La directive proxy_buffering off
  6. Utilisation incorrecte de la directive if
  7. Contrôles de santé excessifs
  8. Accès non sécurisé aux métriques
  9. Utilisation de ip_hash lorsque tout le trafic provient du même bloc CIDR /24
  10. Ne pas profiter des groupes en amont

Erreur 1 : Pas assez de descripteurs de fichiers par travailleur

La directive worker_connections définit le nombre maximal de connexions simultanées qu'un processus de travail NGINX peut avoir ouvertes (la valeur par défaut est 512). Tous les types de connexions (par exemple, les connexions avec des serveurs proxy) sont comptabilisés dans le maximum, pas seulement les connexions client. Mais il est important de garder à l'esprit qu'en fin de compte, il existe une autre limite au nombre de connexions simultanées par travailleur : la limite du système d'exploitation sur le nombre maximal de descripteurs de fichiers (FD) alloués à chaque processus. Dans les distributions UNIX modernes, la limite par défaut est 1024.

Pour tous les déploiements NGINX, à l’exception des plus petits, une limite de 512 connexions par worker est probablement trop petite. En effet, le fichier nginx.conf par défaut que nous distribuons avec les binaires NGINX Open Source et NGINX Plus l'augmente à 1024.

L'erreur de configuration courante consiste à ne pas augmenter la limite des FD à au moins deux fois la valeur de worker_connections . La solution consiste à définir cette valeur avec la directive worker_rlimit_nofile dans le contexte de configuration principal.

Voici pourquoi davantage de FD sont nécessaires : chaque connexion d’un processus de travail NGINX à un client ou à un serveur en amont consomme un FD. Lorsque NGINX agit en tant que serveur Web, il utilise un FD pour la connexion client et un FD par fichier servi, pour un minimum de deux FD par client (mais la plupart des pages Web sont créées à partir de plusieurs fichiers). Lorsqu'il agit comme serveur proxy, NGINX utilise un FD pour la connexion au client et au serveur en amont, et potentiellement un troisième FD pour le fichier utilisé pour stocker temporairement la réponse du serveur. En tant que serveur de mise en cache, NGINX se comporte comme un serveur Web pour les réponses mises en cache et comme un serveur proxy si le cache est vide ou expiré.

NGINX utilise également un FD par fichier journal et quelques FD pour communiquer avec le processus maître, mais généralement ces nombres sont faibles par rapport au nombre de FD utilisés pour les connexions et les fichiers.

UNIX propose plusieurs façons de définir le nombre de FD par processus :

  • La commande ulimit si vous démarrez NGINX à partir d'un shell
  • Les variables du manifeste du script d'initialisation ou du service systemd si vous démarrez NGINX en tant que service
  • Le fichier /etc/security/limits.conf

Cependant, la méthode à utiliser dépend de la manière dont vous démarrez NGINX, alors que worker_rlimit_nofile fonctionne quelle que soit la manière dont vous démarrez NGINX.

Il existe également une limite à l'échelle du système sur le nombre de FD, que vous pouvez définir avec la commande sysctl fs.file-max du système d'exploitation. Il est généralement suffisamment grand, mais il vaut la peine de vérifier que le nombre maximal de descripteurs de fichiers que tous les processus de travail NGINX peuvent utiliser ( worker_rlimit_nofile * worker_processes ) est nettement inférieur à fs.file‑max . Si NGINX utilise d'une manière ou d'une autre tous les FD disponibles (par exemple, lors d'une attaque DoS), il devient impossible de se connecter à la machine pour résoudre le problème.

Erreur 2 : La directive error_log off

L’erreur courante est de penser que la directive error_log off désactive la journalisation. En fait, contrairement à la directive access_log , error_log ne prend pas de paramètre off . Si vous incluez la directive error_log off dans la configuration, NGINX crée un fichier journal d'erreurs nommé off dans le répertoire par défaut des fichiers de configuration NGINX (généralement /etc/nginx ).

Nous ne recommandons pas de désactiver le journal des erreurs, car il s’agit d’une source d’informations essentielle lors du débogage de tout problème avec NGINX. Cependant, si le stockage est si limité qu’il est possible d’enregistrer suffisamment de données pour épuiser l’espace disque disponible, il peut être judicieux de désactiver la journalisation des erreurs. Inclure cette directive dans le contexte de configuration principal :

journal_d'erreur /dev/null émerge ;

Notez que cette directive ne s'applique pas tant que NGINX n'a pas lu et validé la configuration. Ainsi, chaque fois que NGINX démarre ou que la configuration est rechargée, elle peut être enregistrée dans l'emplacement du journal des erreurs par défaut (généralement /var/log/nginx/error.log ) jusqu'à ce que la configuration soit validée. Pour modifier le répertoire du journal, incluez le paramètre -e < error_log_location > dans la commande nginx .

Erreur 3 : Ne pas activer les connexions Keepalive aux serveurs en amont

Par défaut, NGINX ouvre une nouvelle connexion à un serveur en amont (backend) pour chaque nouvelle demande entrante. C'est sûr mais inefficace, car NGINX et le serveur doivent échanger trois paquets pour établir une connexion et trois ou quatre pour la terminer.

Lorsque le volume de trafic est élevé, l'ouverture d'une nouvelle connexion pour chaque demande peut épuiser les ressources du système et rendre impossible l'ouverture de connexions. Voici pourquoi : pour chaque connexion, le quadruple composé de l’adresse source, du port source, de l’adresse de destination et du port de destination doit être unique. Pour les connexions de NGINX à un serveur en amont, trois des éléments (le premier, le troisième et le quatrième) sont fixes, ne laissant que le port source comme variable. Lorsqu'une connexion est fermée, le socket Linux reste dans l'état TIME-WAIT pendant deux minutes, ce qui, en cas de volumes de trafic élevés, augmente la possibilité d'épuiser le pool de ports sources disponibles. Si cela se produit, NGINX ne peut pas ouvrir de nouvelles connexions aux serveurs en amont.

La solution consiste à activer les connexions persistantes entre NGINX et les serveurs en amont : au lieu d’être fermée lorsqu’une demande est terminée, la connexion reste ouverte pour être utilisée pour des demandes supplémentaires. Cela réduit à la fois la possibilité de manquer de ports sources et améliore les performances .

Pour activer les connexions persistantes :

  • Incluez la directive keepalive dans chaque bloc upstream{} , pour définir le nombre de connexions keepalive inactives aux serveurs en amont conservées dans le cache de chaque processus de travail.

    Notez que la directive keepalive ne limite pas le nombre total de connexions aux serveurs en amont qu’un processus de travail NGINX peut ouvrir – c’est une idée fausse courante. Ainsi, le paramètre à maintenir en vie n’a pas besoin d’être aussi grand que vous pourriez le penser.

    Nous vous recommandons de définir le paramètre sur deux fois le nombre de serveurs répertoriés dans le bloc upstream{} . Cela est suffisamment grand pour que NGINX puisse maintenir des connexions persistantes avec tous les serveurs, mais suffisamment petit pour que les serveurs en amont puissent également traiter les nouvelles connexions entrantes.

    Notez également que lorsque vous spécifiez un algorithme d'équilibrage de charge dans le bloc upstream{} (avec la directive hash , ip_hash , least_conn , least_time ou random ), la directive doit apparaître au-dessus de la directive keepalive . Il s’agit de l’une des rares exceptions à la règle générale selon laquelle l’ordre des directives dans la configuration NGINX n’a pas d’importance.

  • Dans le bloc location{} qui transmet les requêtes à un groupe en amont, incluez les directives suivantes avec la directive proxy_pass :

    proxy_http_version 1.1;
    proxy_set_header "Connexion" "";
    

    Par défaut, NGINX utilise HTTP/1.0 pour les connexions aux serveurs en amont et ajoute en conséquence l'en-tête Connection: close aux requêtes qu'il transmet aux serveurs. Le résultat est que chaque connexion est fermée lorsque la requête est terminée, malgré la présence de la directive keepalive dans le bloc upstream{} .

    La directive proxy_http_version indique à NGINX d'utiliser HTTP/1.1 à la place, et la directive proxy_set_header supprime la valeur close de l'en-tête de connexion .

Erreur 4 : Oublier comment fonctionne l'héritage directif

Les directives NGINX sont héritées vers le bas, ou « de l'extérieur vers l'intérieur » : un contexte enfant (imbriqué dans un autre contexte (son parent )) hérite des paramètres des directives incluses au niveau parent. Par exemple, tous les blocs server{} et location{} dans le contexte http{} héritent de la valeur des directives incluses au niveau http , et une directive dans un bloc server{} est héritée par tous les blocs enfants location{} qu'il contient. Cependant, lorsque la même directive est incluse à la fois dans un contexte parent et dans son contexte enfant, les valeurs ne sont pas additionnées : au lieu de cela, la valeur du contexte enfant remplace la valeur parent.

L’erreur est d’oublier cette « règle de remplacement » pour les directives de tableau , qui peuvent être incluses non seulement dans plusieurs contextes mais également plusieurs fois dans un contexte donné. Les exemples incluent proxy_set_header et add_header – avoir « add » dans le nom du second rend particulièrement facile l’oubli de la règle de remplacement.

Nous pouvons illustrer le fonctionnement de l'héritage avec cet exemple pour add_header :

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

serveur {
écoute 8080;
emplacement / {
retour 200 "OK";
} 
}

serveur {
écoute 8081;
add_header X-SERVER-LEVEL-HEADER 1;

emplacement / {
retour 200 "OK";
}

emplacement /test {
add_header X-LOCATION-LEVEL-HEADER 1;
retour 200 "OK";
}

emplacement /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 ;
retour 200 "OK" ;
} 
}
}

Pour le serveur écoutant sur le port 8080, il n'y a aucune directive add_header dans les blocs server{} ou location{} . L'héritage est donc simple et nous voyons les deux en-têtes définis dans le contexte http{} :

% curl -i localhost:8080 HTTP/1.1 200 OK Serveur : nginx/1.21.5 Date : lun. 21 févr. 2022 10:12:15 GMT Type de contenu : text/plain Longueur du contenu : 2 Connexion : keep-alive X-HTTP-LEVEL-HEADER : 1 X-UN AUTRE-EN-TÊTE-DE-NIVEAU-HTTP : 1 d'accord

Pour le serveur écoutant sur le port 8081, il existe une directive add_header dans le bloc server{} mais pas dans son emplacement / bloc enfant. L'en-tête défini dans le bloc server{} remplace les deux en-têtes définis dans le contexte http{} :

% curl -i localhost:8081 HTTP/1.1 200 OK Serveur : nginx/1.21.5 Date : lun. 21 févr. 2022 10:12:20 GMT Type de contenu : text/plain Longueur du contenu : 2 Connexion : keep-alive X-SERVER-LEVEL-HEADER : 1 d'accord

Dans le bloc d'emplacement enfant /test , il existe une directive add_header et elle remplace à la fois l'en-tête de son bloc parent server{} et les deux en-têtes du contexte http{} :

% curl -i localhost:8081/test HTTP/1.1 200 OK Serveur : nginx/1.21.5 Date : lun. 21 févr. 2022 10:12:25 GMT Type de contenu : text/plain Longueur du contenu : 2 Connexion : keep-alive X-LOCATION-LEVEL-HEADER : 1 d'accord

Si nous voulons qu'un bloc location{} conserve les en-têtes définis dans ses contextes parents ainsi que tous les en-têtes définis localement, nous devons redéfinir les en-têtes parents dans le bloc location{} . C'est ce que nous avons fait dans le bloc location /correct :

% curl -i localhost:8081/correct HTTP/1.1 200 OK Serveur : nginx/1.21.5 Date : lun. 21 févr. 2022 10:12:30 GMT Type de contenu : text/plain Longueur du contenu : 2 Connexion : keep-alive X-HTTP-LEVEL-HEADER : 1 X-UN AUTRE-EN-TÊTE-DE-NIVEAU-HTTP : 1 EN-TÊTE DE NIVEAU DU SERVEUR X : 1 EN-TÊTE DE NIVEAU D'EMPLACEMENT X : 1 d'accord

Erreur 5 : La directive proxy_buffering off

La mise en mémoire tampon du proxy est activée par défaut dans NGINX (la directive proxy_buffering est définie sur on ). La mise en mémoire tampon du proxy signifie que NGINX stocke la réponse d'un serveur dans des tampons internes au fur et à mesure de son arrivée et ne commence pas à envoyer de données au client tant que la réponse entière n'est pas mise en mémoire tampon. La mise en mémoire tampon permet d'optimiser les performances avec les clients lents. Étant donné que NGINX met la réponse en mémoire tampon aussi longtemps que nécessaire pour que le client la récupère dans son intégralité, le serveur proxy peut renvoyer sa réponse le plus rapidement possible et redevenir disponible pour répondre à d'autres requêtes.

Lorsque la mise en mémoire tampon du proxy est désactivée, NGINX met en mémoire tampon uniquement la première partie de la réponse d'un serveur avant de commencer à l'envoyer au client, dans une mémoire tampon dont la taille par défaut est d'une page mémoire (4 Ko ou 8 Ko selon le système d'exploitation). Il s'agit généralement d'un espace suffisant pour l'en-tête de réponse. NGINX envoie ensuite la réponse au client de manière synchrone au fur et à mesure qu'il la reçoit, forçant le serveur à rester inactif en attendant que NGINX puisse accepter le segment de réponse suivant.

Nous sommes donc surpris de la fréquence à laquelle nous voyons proxy_buffering désactivé dans les configurations. Il est peut-être prévu de réduire la latence subie par les clients, mais l'effet est négligeable alors que les effets secondaires sont nombreux : avec la mise en mémoire tampon du proxy désactivée, la limitation du débit et la mise en cache ne fonctionnent pas même si elles sont configurées, les performances en souffrent, etc.

Il n'existe qu'un petit nombre de cas d'utilisation dans lesquels la désactivation de la mise en mémoire tampon du proxy peut avoir du sens (comme une interrogation longue), nous déconseillons donc fortement de modifier la valeur par défaut. Pour plus d'informations, consultez le Guide d'administration NGINX Plus .

Erreur 6 : Utilisation incorrecte de la directive if

La directive if est délicate à utiliser, en particulier dans les blocs location{} . Il ne fait souvent pas ce que vous attendez et peut même provoquer des erreurs de segmentation. En fait, c'est tellement délicat qu'il existe un article intitulé If is Evil dans le wiki NGINX, et nous vous y dirigeons pour une discussion détaillée des problèmes et comment les éviter.

En général, les seules directives que vous pouvez toujours utiliser en toute sécurité dans un bloc if{} sont return et rewrite . L'exemple suivant utilise if pour détecter les requêtes qui incluent l'en-tête X-Test (mais cela peut être n'importe quelle condition que vous souhaitez tester). NGINX renvoie le430 ( Champs d' en-tête de demande trop grands) , l'intercepte à l'emplacement nommé @error_430 et transmet la demande au groupe en amont nommé b .

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

proxy_pass http://a;
}

emplacement @error_430 {
proxy_pass b;
}

Pour cette utilisation et bien d'autres de if , il est souvent possible d'éviter complètement la directive. Dans l'exemple suivant, lorsque la requête inclut l'en-tête X-Test, le bloc map{} définit la variable $upstream_name sur b et la requête est transmise par proxy au groupe en amont portant ce nom.

carte $http_x_test $upstream_name { 
par défaut "b";
"" "a";
}

# ...

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

Erreur 7 : Contrôles de santé excessifs

Il est assez courant de configurer plusieurs serveurs virtuels pour transmettre des requêtes au même groupe en amont (en d'autres termes, pour inclure la même directive proxy_pass dans plusieurs blocs server{} ). L’erreur dans cette situation est d’inclure une directive health_check dans chaque bloc server{} . Cela crée simplement plus de charge sur les serveurs en amont sans fournir d’informations supplémentaires.

Au risque d’être évident, la solution consiste à définir un seul contrôle de santé par bloc en amont . Ici, nous définissons le contrôle de santé pour le groupe en amont nommé b dans un emplacement nommé spécial, avec des délais d'expiration et des paramètres d'en-tête appropriés.

emplacement / { 
proxy_set_header Hôte $host;
proxy_set_header "Connexion" "";
proxy_http_version 1.1;
proxy_pass http://b;
}

emplacement @health_check {
health_check;
proxy_connect_timeout 2s;
proxy_read_timeout 3s;
proxy_set_header Hôte example.com;
proxy_pass http://b;
}

Dans les configurations complexes, il peut être encore plus simple de regrouper tous les emplacements de contrôle d’état sur un seul serveur virtuel avec l’ API NGINX Plus et le tableau de bord, comme dans cet exemple.

serveur { 
écouter 8080 ;

emplacement / {
# …
}

emplacement @health_check_b {
health_check ;
proxy_connect_timeout 2s ;
proxy_read_timeout 3s ;
proxy_set_header Hôte example.com ;
proxy_pass http://b ;
}

emplacement @health_check_c {
health_check ;
proxy_connect_timeout 2s ;
proxy_read_timeout 3s ;
proxy_set_header Hôte api.example.com ;
proxy_pass http://c ;
}

emplacement /api {
api write=on ;
# directives limitant l'accès à l'API (voir « Erreur 8 » ci-dessous)
}

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

Pour plus d'informations sur les contrôles de santé des serveurs HTTP, TCP, UDP et gRPC, consultez le Guide d'administration NGINX Plus .

Erreur 8 : Accès non sécurisé aux mesures

Les mesures de base sur le fonctionnement de NGINX sont disponibles à partir du module Stub Status . Pour NGINX Plus, vous pouvez également collecter un ensemble de mesures beaucoup plus complet avec l' API NGINX Plus . Activez la collecte de mesures en incluant respectivement la directive stub_status ou api dans un bloc server{} ou location{} , qui devient l'URL à laquelle vous accédez ensuite pour afficher les mesures. (Pour l' API NGINX Plus , vous devez également configurer des zones de mémoire partagée pour les entités NGINX (serveurs virtuels, groupes en amont, caches, etc.) pour lesquelles vous souhaitez collecter des métriques ; consultez les instructions du Guide d'administration NGINX Plus .)

Certaines des mesures sont des informations sensibles qui peuvent être utilisées pour attaquer votre site Web ou les applications proxy par NGINX, et l'erreur que nous voyons parfois dans les configurations utilisateur est l'échec de la restriction de l'accès à l'URL correspondante. Nous examinons ici certaines des manières dont vous pouvez sécuriser les métriques. Nous utiliserons stub_status dans les premiers exemples.

Avec la configuration suivante, toute personne sur Internet peut accéder aux métriques à l' adresse http://example.com/basic_status .

serveur { 
écouter 80 ;
nom_serveur exemple.com ;

emplacement = /statut_de_base {
statut_stub ;
}
}

Protégez vos métriques avec l'authentification HTTP de base

Pour protéger par mot de passe les métriques avec l’authentification HTTP de base , incluez les directives auth_basic et auth_basic_user_file . Le fichier (ici, .htpasswd ) répertorie les noms d'utilisateur et les mots de passe des clients qui peuvent se connecter pour voir les métriques :

serveur { 
écouter 80 ;
nom_serveur exemple.com ;

emplacement = /basic_status {
auth_basic « site fermé » ;
auth_basic_user_file conf.d/.htpasswd ;
}
}

Protégez les métriques avec les directives allow et deny

Si vous ne souhaitez pas que les utilisateurs autorisés aient à se connecter et que vous connaissez les adresses IP à partir desquelles ils accéderont aux métriques, une autre option est la directive allow . Vous pouvez spécifier des adresses IPv4 et IPv6 individuelles et des plages CIDR. La directive deny all empêche l'accès à partir de toute autre adresse.

serveur { 
écouter 80 ;
nom_serveur exemple.com ;

emplacement = /statut_de_base {
autoriser 192.168.1.0/24 ;
autoriser 10.1.1.0/16 ;
autoriser 2001:0db8::/32 ;
autoriser 96.1.2.23/32 ;
refuser tout ;
statut_stub ;
}
}

Combinez les deux méthodes

Et si nous voulions combiner les deux méthodes ? Nous pouvons permettre aux clients d'accéder aux métriques à partir d'adresses spécifiques sans mot de passe et exiger toujours une connexion pour les clients provenant d'adresses différentes. Pour cela, nous utilisons la directive meet any . Il indique à NGINX d'autoriser l'accès aux clients qui se connectent avec les informations d'identification d'authentification HTTP de base ou qui utilisent une adresse IP pré-approuvée. Pour plus de sécurité, vous pouvez définir « satisfaire à tous » pour obliger même les personnes provenant d'adresses spécifiques à se connecter.

serveur { 
écouter 80 ;
nom_serveur moniteur.exemple.com ;

emplacement = /basic_status {
satisfaire à tout ;

auth_basic « site fermé » ;
auth_basic_user_file conf.d/.htpasswd ;
autoriser 192.168.1.0/24 ;
autoriser 10.1.1.0/16 ;
autoriser 2001:0db8::/32 ;
autoriser 96.1.2.23/32 ;
refuser tout ;
stub_status ;
}
}

Avec NGINX Plus, vous utilisez les mêmes techniques pour limiter l'accès au point de terminaison de l' API NGINX Plus ( http://monitor.example.com:8080/api/ dans l'exemple suivant) ainsi qu'au tableau de bord de surveillance des activités en direct à l' adresse http://monitor.example.com/dashboard.html .

Cette configuration permet l'accès sans mot de passe uniquement aux clients provenant du réseau 96.1.2.23/32 ou localhost. Étant donné que les directives sont définies au niveau du serveur , les mêmes restrictions s’appliquent à la fois à l’API et au tableau de bord. En remarque, le paramètre write=on de l'API signifie que ces clients peuvent également utiliser l'API pour apporter des modifications de configuration.

Pour plus d'informations sur la configuration de l'API et du tableau de bord, consultez le Guide d'administration NGINX Plus .

serveur { 
écouter 8080 ;
nom_serveur moniteur.exemple.com ;

satisfaire tout ;
auth_basic « site fermé » ;
auth_basic_user_file conf.d/.htpasswd ;
autoriser 127.0.0.1/32 ;
autoriser 96.1.2.23/32 ;
refuser tout ;

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

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

Erreur 9 : Utilisation de ip_hash lorsque tout le trafic provient du même bloc CIDR /24

L'algorithme ip_hash équilibre la charge du trafic sur les serveurs dans un bloc en amont , en fonction d'un hachage de l'adresse IP du client. La clé de hachage correspond aux trois premiers octets d'une adresse IPv4 ou à l'adresse IPv6 entière. La méthode établit la persistance de session, ce qui signifie que les demandes d'un client sont toujours transmises au même serveur, sauf lorsque le serveur n'est pas disponible.

Supposons que nous ayons déployé NGINX comme proxy inverse dans un réseau privé virtuel configuré pour une haute disponibilité. Nous mettons en place divers pare-feu, routeurs, équilibreurs de charge de couche 4 et passerelles devant NGINX pour accepter le trafic provenant de différentes sources (le réseau interne, les réseaux partenaires, Internet, etc.) et le transmettre à NGINX pour le proxy inverse vers les serveurs en amont. Voici la configuration initiale de NGINX :

http {
en amont {
ip_hash;
serveur 10.10.20.105:8080;
serveur 10.10.20.106:8080;
serveur 10.10.20.108:8080;
}

serveur {# …}
}

Mais il s'avère qu'il y a un problème : tous les appareils « d'interception » sont sur le même réseau 10.10.0.0/24, donc pour NGINX, il semble que tout le trafic provient d'adresses dans cette plage CIDR. N'oubliez pas que l'algorithme ip_hash hache les trois premiers octets d'une adresse IPv4. Dans notre déploiement, les trois premiers octets sont les mêmes – 10.10.0 – pour chaque client, donc le hachage est le même pour tous et il n'y a aucune base pour distribuer le trafic vers différents serveurs.

La solution consiste à utiliser l’algorithme de hachage à la place avec la variable $binary_remote_addr comme clé de hachage. Cette variable capture l'adresse client complète, la convertissant en une représentation binaire de 4 octets pour une adresse IPv4 et de 16 octets pour une adresse IPv6. Désormais, le hachage est différent pour chaque périphérique d’interception et l’équilibrage de charge fonctionne comme prévu.

Nous incluons également le paramètre cohérent pour utiliser la méthode de hachage ketama au lieu de la valeur par défaut. Cela réduit considérablement le nombre de clés qui sont remappées sur un autre serveur en amont lorsque l'ensemble de serveurs change, ce qui produit un taux de réussite du cache plus élevé pour les serveurs de mise en cache.

http { 
en amont {
hachage $binary_remote_addr cohérent ;
serveur 10.10.20.105 : 8080 ;
serveur 10.10.20.106 : 8080 ;
serveur 10.10.20.108 : 8080 ;
}

serveur {# …}
}

Erreur 10 : Ne pas tirer profit des groupes en amont

Supposons que vous utilisiez NGINX pour l’un des cas d’utilisation les plus simples, en tant que proxy inverse pour une seule application back-end basée sur NodeJS écoutant sur le port 3000. Une configuration courante pourrait ressembler à ceci :

http {
serveur {
écoute 80 ;
nom_serveur exemple.com ;

emplacement / {
en-tête_proxy_set Hôte $host ;
pass_proxy http://localhost:3000/ ;
}
}
}

C'est simple, n'est-ce pas ? La directive proxy_pass indique à NGINX où envoyer les requêtes des clients. Tout ce que NGINX doit faire est de résoudre le nom d’hôte en une adresse IPv4 ou IPv6. Une fois la connexion établie, NGINX transmet les demandes à ce serveur.

L'erreur ici est de supposer que, comme il n'y a qu'un seul serveur (et donc aucune raison de configurer l'équilibrage de charge), il est inutile de créer un bloc en amont . En fait, un bloc en amont débloque plusieurs fonctionnalités qui améliorent les performances, comme l'illustre cette configuration :

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 directive zone établit une zone de mémoire partagée où tous les processus de travail NGINX sur l'hôte peuvent accéder aux informations de configuration et d'état sur les serveurs en amont. Plusieurs groupes en amont peuvent partager la zone. Avec NGINX Plus, la zone vous permet également d'utiliser l' API NGINX Plus pour modifier les serveurs d'un groupe en amont et les paramètres des serveurs individuels sans redémarrer NGINX. Pour plus de détails, consultez le Guide d'administration de NGINX Plus .

La directive serveur dispose de plusieurs paramètres que vous pouvez utiliser pour régler le comportement du serveur. Dans cet exemple, nous avons modifié les conditions utilisées par NGINX pour déterminer qu’un serveur n’est pas sain et n’est donc pas éligible pour accepter des demandes. Ici, un serveur est considéré comme non sain si une tentative de communication échoue même une fois toutes les 2 secondes (au lieu de la valeur par défaut d'une fois toutes les 10 secondes ).

Nous combinons ce paramètre avec la directive proxy_next_upstream pour configurer ce que NGINX considère comme une tentative de communication ayant échoué, auquel cas il transmet les requêtes au serveur suivant du groupe en amont. Aux conditions d'erreur et de délai d'attente par défaut, nous ajoutons http_500 afin que NGINX considère un HTTP 500( Erreur interne du serveur ) code provenant d'un serveur en amont pour représenter une tentative infructueuse.

La directive keepalive définit le nombre de connexions keepalive inactives aux serveurs en amont conservées dans le cache de chaque processus de travail. Nous avons déjà discuté des avantages de l’erreur 3 : Ne pas activer les connexions Keepalive aux serveurs en amont .

Avec NGINX Plus, vous pouvez configurer des fonctionnalités supplémentaires avec des groupes en amont :

  • Nous avons mentionné ci-dessus que NGINX Open Source résout les noms d'hôtes du serveur en adresses IP une seule fois, lors du démarrage. Le paramètre resolve de la directive server permet à NGINX Plus de surveiller les modifications apportées aux adresses IP qui correspondent au nom de domaine d'un serveur en amont et de modifier automatiquement la configuration en amont sans avoir besoin de redémarrer.

    Le paramètre de service permet également à NGINX Plus d'utiliser les enregistrements DNS SRV , qui incluent des informations sur les numéros de port, les poids et les priorités. Ceci est essentiel dans les environnements de microservices où les numéros de port des services sont souvent attribués de manière dynamique.

    Pour plus d’informations sur la résolution des adresses de serveur, consultez Utilisation de DNS pour la découverte de services avec NGINX et NGINX Plus sur notre blog.

  • Le paramètre slow_start de la directive server permet à NGINX Plus d'augmenter progressivement le volume de requêtes qu'il envoie à un serveur nouvellement considéré comme sain et disponible pour accepter les requêtes. Cela évite un afflux soudain de requêtes qui pourrait submerger le serveur et provoquer une nouvelle panne.

  • La directive queue permet à NGINX Plus de placer des requêtes dans une file d'attente lorsqu'il n'est pas possible de sélectionner un serveur en amont pour traiter la requête, au lieu de renvoyer immédiatement une erreur au client.

Ressources

Pour essayer NGINX Plus, démarrez votre essai gratuit de 30 jours dès aujourd'hui ou contactez-nous pour discuter de vos cas d'utilisation .


« Cet article de blog peut faire référence à des produits qui ne sont plus disponibles et/ou qui ne sont plus pris en charge. Pour obtenir les informations les plus récentes sur les produits et solutions F5 NGINX disponibles, explorez notre famille de produits NGINX . NGINX fait désormais partie de F5. Tous les liens NGINX.com précédents redirigeront vers un contenu NGINX similaire sur F5.com."