Comprendre la structure du fichier de configuration Nginx et les contextes de configuration

introduction

Nginx est un serveur Web hautes performances chargé de gérer la charge de certains des plus grands sites sur Internet. Il est particulièrement efficace pour gérer de nombreuses connexions simultanées et excelle pour la fourniture de contenu statique.

Bien que de nombreux utilisateurs connaissent les fonctionnalités de Nginx, les nouveaux utilisateurs sont souvent déconcertés par certaines des conventions qu’ils trouvent dans les fichiers de configuration de Nginx. Dans ce guide, nous discuterons de la structure de base d’un fichier de configuration Nginx et de quelques instructions pour la conception de vos fichiers.

Comprendre les contextes de configuration de Nginx

Ce guide couvrira la structure de base trouvée dans le fichier de configuration principal de Nginx. L’emplacement de ce fichier dépend de la manière dont vous avez installé le logiciel sur votre ordinateur. Pour de nombreuses distributions, le fichier sera situé dans + / etc / nginx / nginx.conf +. S’il n’existe pas là-bas, il peut également s’agir de + / usr / local / nginx / conf / nginx.conf + ou + / usr / local / etc / nginx / nginx.conf +.

Une des premières choses que vous devriez remarquer lorsque vous regardez le fichier de configuration principal est qu’il semble être organisé en une structure arborescente, définie par des ensembles de crochets (qui ressemblent à + ​​{+ et +} + ). Dans le jargon de Nginx, les zones définies par ces crochets sont appelées «contextes», car elles contiennent des détails de configuration séparés en fonction de leur domaine de préoccupation. Fondamentalement, ces divisions fournissent une structure organisationnelle accompagnée d’une logique conditionnelle pour décider d’appliquer ou non les configurations à l’intérieur.

Étant donné que les contextes peuvent être superposés, Nginx fournit un niveau d’héritage de directive. En règle générale, si une directive est valide dans plusieurs portées imbriquées, une déclaration dans un contexte plus large sera transmise à tous les contextes enfants en tant que valeurs par défaut. Les contextes enfants peuvent remplacer ces valeurs à volonté. Il est à noter qu’un remplacement de toute directive de type tableau remplacera la valeur précédente sans l’ajouter.

Les directives ne peuvent être utilisées que dans les contextes pour lesquels elles ont été conçues. Nginx rencontrera une erreur lors de la lecture d’un fichier de configuration avec des directives déclarées dans un contexte incorrect. La Nginx documentation contient des informations sur les contextes dans lesquels chaque directive est valide. Il constitue donc une excellente référence en cas de doute.

Ci-dessous, nous aborderons les contextes les plus courants que vous êtes susceptible de rencontrer lorsque vous travaillez avec Nginx.

Les contextes fondamentaux

Le premier groupe de contextes que nous allons aborder est constitué des contextes centraux que Nginx utilise pour créer un arbre hiérarchique et séparer les préoccupations des blocs de configuration discrets. Ce sont les contextes qui constituent la structure principale d’une configuration Nginx.

Le contexte principal

Le contexte le plus général est le contexte «principal» ou «global». C’est le seul contexte qui ne soit pas contenu dans les blocs de contexte typiques qui ressemblent à ceci:

# The main context is here, outside any other contexts

. . .

{

   . . .

}

Toute directive qui existe entièrement en dehors de ces blocs est réputée habiter le contexte «principal». N’oubliez pas que si votre configuration Nginx est configurée de manière modulaire, certains fichiers contiendront des instructions qui semblent exister en dehors d’un contexte entre crochets, mais qui seront incluses dans un tel contexte lorsque la configuration est assemblée.

Le contexte principal représente l’environnement le plus large pour la configuration de Nginx. Il est utilisé pour configurer les détails qui affectent l’ensemble de l’application à un niveau de base. Bien que les directives de cette section affectent les contextes inférieurs, bon nombre d’entre elles ne sont pas héritées car elles ne peuvent pas être remplacées aux niveaux inférieurs.

Parmi les détails courants configurés dans le contexte principal, figurent l’utilisateur et le groupe sur lesquels les processus de travail doivent être exécutés, le nombre de travailleurs et le fichier dans lequel enregistrer le PID du processus principal. Vous pouvez même définir des éléments tels que l’affinité entre les processeurs et la «gentillesse» des processus de travail. Le fichier d’erreur par défaut pour l’ensemble de l’application peut être défini à ce niveau (il peut être remplacé dans des contextes plus spécifiques).

Le contexte des événements

Le contexte «événements» est contenu dans le contexte «principal». Il est utilisé pour définir des options globales qui affectent la manière dont Nginx gère les connexions à un niveau général. Il ne peut y avoir qu’un seul contexte d’événements défini dans la configuration de Nginx.

Ce contexte ressemblera à ceci dans le fichier de configuration, en dehors de tout autre contexte entre crochets:

# main context

events {

   # events context
   . . .

}

Nginx utilise un modèle de traitement de connexion basé sur des événements. Par conséquent, les directives définies dans ce contexte déterminent la manière dont les processus de travail doivent gérer les connexions. Les directives trouvées ici sont principalement utilisées pour sélectionner la technique de traitement de connexion à utiliser ou pour modifier la façon dont ces méthodes sont implémentées.

Généralement, la méthode de traitement de la connexion est automatiquement sélectionnée en fonction du choix le plus efficace disponible sur la plate-forme. Pour les systèmes Linux, la méthode + epoll + est généralement le meilleur choix.

Les autres éléments pouvant être configurés sont le nombre de connexions que chaque travailleur peut gérer, si un travailleur ne prendra qu’une connexion à la fois ou toutes les connexions en attente après avoir été averti d’une connexion en attente, et si les travailleurs répondent à tour de rôle aux événements. .

Le contexte HTTP

Lors de la configuration de Nginx en tant que serveur Web ou proxy inverse, le contexte «http» contiendra la majorité de la configuration. Ce contexte contiendra toutes les directives et autres contextes nécessaires pour définir la manière dont le programme gérera les connexions HTTP ou HTTPS.

Le contexte http est un frère du contexte des événements. Ils doivent donc être répertoriés côte à côte plutôt que imbriqués. Ils sont tous deux des enfants du contexte principal:

# main context

events {
   # events context

   . . .

}

http {
   # http context

   . . .

}

Tandis que les contextes inférieurs décrivent plus précisément la manière de gérer les demandes, les directives de ce niveau contrôlent les valeurs par défaut de chaque serveur virtuel défini dans celui-ci. Un grand nombre de directives sont configurables dans ce contexte et au-dessous, en fonction de la manière dont vous souhaitez que l’héritage fonctionne.

Certaines des directives que vous êtes susceptible de rencontrer contrôlent les emplacements par défaut pour les journaux d’accès et d’erreurs (+ access_log + et + error_log +), configurent les E / S asynchrones pour les opérations sur les fichiers (+ aio +, + + sendfile + , et `+ directio +), et configurez les statuts du serveur en cas d’erreur (+ error_page +). D’autres directives configurent la compression (+ gzip + et + gzip_disable +), affinent les paramètres de maintien TCP actifs (+ keepalive_disable +, + keepalive_requests + et + keepalive_timeout +), ainsi que les règles suivies par Nginx essayez d’optimiser les paquets et les appels système (+ sendfile +, + tcp_nodelay + et + tcp_nopush +). Des directives supplémentaires configurent un fichier racine et des fichiers d’index au niveau de l’application (+ root + et + + index + ) et configurent les différentes tables de hachage utilisées pour stocker différents types de données ( + * _ hash_bucket_size + et + * _ hash_max_size + `pour + noms_serveur + , + types + , et + variables + `).

Le contexte du serveur

Le contexte "serveur" est déclaré dans le contexte "http". Ceci est notre premier exemple de contextes imbriqués, entre crochets. C’est également le premier contexte qui permet plusieurs déclarations.

Le format général du contexte de serveur peut ressembler à ceci. Rappelez-vous que ceux-ci résident dans le contexte http:

# main context

http {

   # http context

   server {

       # first server context

   }

   server {

       # second server context

   }

}

La raison pour autoriser plusieurs déclarations du contexte de serveur est que chaque instance définit un serveur virtuel spécifique pour gérer les demandes des clients. Vous pouvez avoir autant de blocs serveur que nécessaire, chacun d’entre eux pouvant gérer un sous-ensemble spécifique de connexions.

En raison de la possibilité et de la probabilité de plusieurs blocs serveur, ce type de contexte est également le premier pour lequel Nginx doit utiliser un algorithme de sélection pour prendre des décisions. Chaque demande client sera traitée selon la configuration définie dans un contexte de serveur unique. Nginx doit donc choisir le contexte de serveur le plus approprié en fonction des détails de la demande. Les directives qui déterminent si un bloc de serveur sera utilisé pour répondre à une demande sont les suivantes:

  • * listen *: combinaison adresse IP / port à laquelle ce bloc de serveur est conçu pour répondre. Si une demande émanant d’un client correspondant à ces valeurs, ce bloc sera potentiellement sélectionné pour gérer la connexion.

  • * nom_serveur *: Cette directive est l’autre composant utilisé pour sélectionner un bloc de serveur à traiter. S’il existe plusieurs blocs de serveur avec des directives d’écoute de même spécificité pouvant gérer la demande, Nginx analysera l’en-tête «Host» de la demande et le comparera à cette directive.

Les directives dans ce contexte peuvent remplacer beaucoup des directives pouvant être définies dans le contexte http, y compris la journalisation, la racine du document, la compression, etc. Outre les directives issues du contexte http, nous pouvons également configurer les fichiers pour tenter de répondre aux requêtes (+ try_files +), émettre des redirections et des réécritures (+ return + et + rewrite +) et définir des paramètres arbitraires. variables (+ set +).

Le contexte de l’emplacement

Le prochain contexte que vous allez traiter régulièrement est le contexte de l’emplacement. Les contextes de localisation partagent de nombreuses qualités relationnelles avec les contextes de serveur. Par exemple, plusieurs contextes d’emplacement peuvent être définis, chaque emplacement est utilisé pour traiter un certain type de demande client et chaque emplacement est sélectionné en faisant correspondre la définition d’emplacement à la demande du client via un algorithme de sélection.

Alors que les directives qui déterminent s’il faut ou non sélectionner un bloc de serveur sont définies dans le serveur context, le composant qui décide de la capacité d’un emplacement à traiter une demande est situé à l’emplacement definition (la ligne qui ouvre le bloc d’emplacement).

La syntaxe générale ressemble à ceci:

location   {

   . . .

}

Les blocs d’emplacement résident dans des contextes de serveur et, contrairement aux blocs de serveur, peuvent être imbriqués les uns dans les autres. Cela peut être utile pour créer un contexte de localisation plus général afin de capturer un certain sous-ensemble de trafic, puis de le traiter en fonction de critères plus spécifiques avec des contextes supplémentaires à l’intérieur:

# main context

server {

   # server context

   location  {

       # first location context

   }

   location  {

       # second location context

       location  {

           # first nested location

       }

       location  {

           # second nested location

       }

   }

}

Alors que les contextes de serveur sont sélectionnés en fonction de la combinaison adresse IP / port demandée et du nom d’hôte dans l’en-tête «Host», les blocs d’emplacement divisent davantage la gestion de la demande dans un bloc de serveur en examinant l’URI de la demande. L’URI de la demande est la partie de la demande qui suit le nom de domaine ou la combinaison adresse IP / port.

Ainsi, si un client demande + http: // www.example.com / blog + sur le port 80, le + http +, + www.example.com + et le port 80 seront tous utilisés pour déterminer quel serveur bloquer pour sélectionner. Une fois le serveur sélectionné, la partie + / blog + (l’URI de la demande) sera évaluée par rapport aux emplacements définis pour déterminer le contexte supplémentaire à utiliser pour répondre à la demande.

La plupart des directives que vous êtes susceptible de voir dans un contexte d’emplacement sont également disponibles aux niveaux parent. Les nouvelles directives de ce niveau vous permettent d’atteindre des emplacements situés en dehors de la racine du document (+ alias +), de marquer l’emplacement comme accessible uniquement en interne (+ internal +)) et d’utiliser un proxy pour les autres serveurs ou emplacements (avec http, fastcgi, scgi , et uwsgi par procuration).

Autres contextes

Bien que les exemples ci-dessus représentent les contextes essentiels que vous rencontrerez avec Nginx, d’autres contextes existent également. Les contextes ci-dessous ont été séparés, soit parce qu’ils dépendent d’un plus grand nombre de modules optionnels, qu’ils ne sont utilisés que dans certaines circonstances, ou qu’ils sont utilisés pour des fonctionnalités que la plupart des gens n’utiliseront pas.

Cependant, nous ne discuterons pas de chacun des contextes disponibles. Les contextes suivants ne seront pas discutés en profondeur:

  • * + split_clients + *: ce contexte est configuré pour diviser les clients que le serveur reçoit en catégories en les étiquetant avec des variables basées sur un pourcentage. Ceux-ci peuvent ensuite être utilisés pour effectuer des tests A / B en fournissant un contenu différent à différents hôtes.

  • * + perl / perl_set + *: Ces contextes configurent les gestionnaires Perl pour l’emplacement dans lequel ils apparaissent. Cela ne sera utilisé que pour le traitement avec Perl.

  • * + map + *: Ce contexte permet de définir la valeur d’une variable en fonction de la valeur d’une autre variable. Il fournit un mappage des valeurs d’une variable pour déterminer l’affectation de la deuxième variable.

  • * + geo + *: Comme le contexte ci-dessus, ce contexte est utilisé pour spécifier un mappage. Cependant, ce mappage est spécifiquement utilisé pour classer les adresses IP des clients. Il définit la valeur d’une variable en fonction de l’adresse IP de connexion.

  • * + types + *: Ce contexte est à nouveau utilisé pour le mappage. Ce contexte est utilisé pour mapper les types MIME aux extensions de fichiers qui devraient leur être associées. Ceci est généralement fourni avec Nginx via un fichier provenant du fichier de configuration principal + nginx.conf +.

  • * + charset_map + *: Ceci est un autre exemple de contexte de mappage. Ce contexte est utilisé pour mapper une table de conversion d’un jeu de caractères à un autre. Dans l’en-tête de contexte, les deux ensembles sont répertoriés et dans le corps, le mappage a lieu.

Les contextes ci-dessous ne sont pas aussi communs que ceux que nous avons discutés jusqu’à présent, mais restent très utiles à connaître.

Le contexte amont

Le contexte en amont est utilisé pour définir et configurer des serveurs «en amont». Fondamentalement, ce contexte définit un pool de serveurs nommés sur lequel Nginx peut ensuite envoyer des requêtes proxy. Ce contexte sera probablement utilisé lorsque vous configurez des mandataires de différents types.

Le contexte en amont doit être placé dans le contexte http, en dehors de tout contexte de serveur spécifique. La forme générale ressemble à ceci:

# main context

http {

   # http context

   upstream  {

       # upstream context

       server ;
       server ;

       . . .

   }

   server {

       # server context

   }

}

Le contexte en amont peut ensuite être référencé par nom dans les blocs de serveur ou d’emplacement pour transmettre les demandes d’un certain type au pool de serveurs défini. L’amont utilisera ensuite un algorithme (round-robin par défaut) pour déterminer le serveur spécifique à qui transmettre la demande. Ce contexte donne à notre Nginx la possibilité d’équilibrer la charge lors de la mise en proxy de demandes.

Le contexte du courrier

Bien que Nginx soit le plus souvent utilisé en tant que serveur Web ou proxy inverse, il peut également fonctionner en tant que serveur proxy de messagerie hautes performances. Le contexte utilisé pour les directives de ce type est appelé, de manière appropriée, "mail". Le contexte de messagerie est défini dans le contexte "principal" ou "global" (en dehors du contexte http).

La fonction principale du contexte de messagerie est de fournir une zone de configuration d’une solution de proxy de messagerie sur le serveur. Nginx peut rediriger les demandes d’authentification vers un serveur d’authentification externe. Il peut ensuite fournir un accès aux serveurs de messagerie POP3 et IMAP pour servir les données de courrier réelles. Le contexte de messagerie peut également être configuré pour se connecter à un relais SMTP si vous le souhaitez.

En général, un contexte de messagerie ressemblera à ceci:

# main context

events {

   # events context

}

mail {

   # mail context

}

Le contexte si

Le contexte «if» peut être établi pour fournir un traitement conditionnel des directives définies dans. Comme une instruction if dans la programmation conventionnelle, la directive if de Nginx exécutera les instructions contenues si un test donné renvoie «true».

Le contexte if dans Nginx est fourni par le module de réécriture et constitue la principale utilisation prévue de ce contexte. Étant donné que Nginx testera les conditions d’une demande avec de nombreuses autres directives spécifiées, ne devrait * pas * être utilisé pour la plupart des formes d’exécution conditionnelle. Ceci est une note tellement importante que la communauté Nginx a créé une page intitulée if is evil.

Le problème est essentiellement que l’ordre de traitement de Nginx peut très souvent conduire à des résultats inattendus qui semblent altérer le sens d’un bloc if. Les seules directives considérées comme sûrement sûres à utiliser à l’intérieur de ces contextes sont les directives + return + et + rewrite + (celles pour lesquelles ce contexte a été créé). Une autre chose à garder à l’esprit lors de l’utilisation d’un contexte if est qu’il rend inutile une directive + try_files + dans le même contexte.

Le plus souvent, un if sera utilisé pour déterminer si une réécriture ou un retour est nécessaire. Celles-ci existeront le plus souvent dans des blocs de localisation, la forme courante ressemblera à ceci:

# main context

http {

   # http context

   server {

       # server context

       location  {

           # location context

           if () {

               # if context

           }

       }

   }

}

Le contexte Limit_except

Le contexte + limit_except + est utilisé pour restreindre l’utilisation de certaines méthodes HTTP dans un contexte d’emplacement. Par exemple, si seuls certains clients doivent avoir accès au contenu POST mais que tout le monde doit avoir la possibilité de lire du contenu, vous pouvez utiliser un bloc + limit_except + pour définir cette exigence.

L’exemple ci-dessus ressemblerait à quelque chose comme ceci:

. . .

# server or location context

location /restricted-write {

   # location context

   limit_except GET HEAD {

       # limit_except context

       allow 192.168.1.1/24;
       deny all;
   }
}

Ceci appliquera les directives à l’intérieur du contexte (destinées à restreindre l’accès) lors de la rencontre de méthodes HTTP * à l’exception de * celles répertoriées dans l’en-tête de contexte. Le résultat de l’exemple ci-dessus est que tout client peut utiliser les verbes GET et HEAD, mais seuls les clients provenant du sous-réseau + 192.168.1.1 / 24 + sont autorisés à utiliser d’autres méthodes.

Règles générales à suivre concernant les contextes

Maintenant que vous avez une idée des contextes courants que vous êtes susceptible de rencontrer lors de l’exploration des configurations Nginx, nous pouvons discuter des meilleures pratiques à utiliser pour gérer les contextes Nginx.

Appliquer des directives dans le contexte le plus élevé disponible

De nombreuses directives sont valables dans plusieurs contextes. Par exemple, de nombreuses directives peuvent être placées dans le contexte http, serveur ou emplacement. Cela nous donne une flexibilité dans l’établissement de ces directives.

Cependant, en règle générale, il est généralement préférable de déclarer les directives dans le contexte le plus élevé auquel elles s’appliquent et de les remplacer, le cas échéant, dans des contextes plus bas. Cela est possible grâce au modèle d’héritage mis en œuvre par Nginx. Il y a plusieurs raisons d’utiliser cette stratégie.

Tout d’abord, déclarer à un niveau élevé vous permet d’éviter les répétitions inutiles entre les contextes frères et sœurs. Par exemple, dans l’exemple ci-dessous, chacun des emplacements déclare la même racine de document:

http {
   server {
       location / {
           root /var/www/html;

           . . .

       }

       location /another {
           root /var/www/html;

           . . .

       }

   }
}

Vous pouvez déplacer la racine vers le bloc serveur, ou même vers le bloc http, comme ceci:

http {
   root /var/www/html;
   server {
       location / {

           . . .

       }

       location /another {

           . . .

       }
   }
}

La plupart du temps, le niveau du serveur sera le plus approprié, mais déclarer au niveau supérieur présente des avantages. Cela vous permet non seulement de définir la directive dans moins d’emplacements, mais également de répartir la valeur par défaut vers tous les éléments enfants, en évitant les situations dans lesquelles vous rencontrez une erreur en oubliant une directive d’un niveau inférieur. Cela peut être un problème majeur avec les longues configurations. Déclarer à des niveaux supérieurs vous fournit une valeur par défaut raisonnable.

Utiliser plusieurs contextes frères et sœurs au lieu de si logique de traitement

Lorsque vous souhaitez traiter les demandes différemment en fonction de certaines informations contenues dans la demande du client, les utilisateurs accèdent souvent au contexte «if» pour tenter de conditionner le traitement. Nous avons brièvement évoqué quelques points à ce sujet.

La première est que la directive «si» renvoie souvent des résultats qui ne correspondent pas aux attentes de l’administrateur. Bien que le traitement aboutisse toujours au même résultat avec la même entrée, la façon dont Nginx interprète l’environnement peut être très différente de ce que l’on peut supposer sans tests lourds.

La deuxième raison à cela est qu’il existe déjà des directives optimisées et conçues à cet effet qui sont utilisées dans bon nombre de ces objectifs. Nginx utilise déjà un algorithme de sélection bien documenté, comme la sélection de blocs de serveur et de blocs d’emplacement. Par conséquent, si cela est possible, il est préférable d’essayer de déplacer vos différentes configurations dans leurs propres blocs afin que cet algorithme puisse gérer la logique du processus de sélection.

Par exemple, au lieu de compter sur les réécritures pour obtenir une requête fournie par l’utilisateur dans le format que vous souhaitez utiliser, vous devriez essayer de configurer deux blocs pour la requête, l’un représentant la méthode souhaitée et l’autre capturant demandes désordonnées et redirections (et éventuellement réécriture) vers votre bloc correct.

Le résultat est généralement plus facile à lire et présente l’avantage supplémentaire d’être plus performant. Les demandes correctes ne subissent aucun traitement supplémentaire et, dans de nombreux cas, des demandes incorrectes peuvent être traitées avec une redirection plutôt qu’une réécriture, qui devrait s’exécuter avec un temps système inférieur.

Conclusion

À ce stade, vous devez bien connaître les contextes les plus courants de Nginx et la directive qui crée les blocs qui les définissent.

Consultez toujours ngin de la documentation de pour obtenir des informations sur les contextes dans lesquels une directive peut être placée et évaluer l’emplacement le plus efficace. Prendre des précautions lors de la création de vos configurations augmentera non seulement la facilité de maintenance, mais augmentera également souvent les performances.