One place for hosting & domains

      Nginx

      Nginx Server- und Standortblockauswahlalgorithmen verstehen


      Einführung

      Nginx ist einer der beliebtesten Webserver der Welt. Er kann hohe Lasten mit vielen gleichzeitigen Clientverbindungen erfolgreich bewältigen und kann problemlos als Webserver, Mailserver oder Reverse-Proxy-Server fungieren.

      In diesem Leitfaden werden wir einige der Details hinter den Kulissen erörtern, die bestimmen, wie Nginx Client-Abfragen verarbeitet. Das Verständnis dieser Ideen kann das Rätselraten beim Entwerfen von Server- und Standortblöcken erleichtern und die Bearbeitung von Abfragen weniger unvorhersehbar erscheinen lassen.

      Nginx-Blockkonfigurationen

      Nginx unterteilt die Konfigurationen, die unterschiedliche Inhalte bereitstellen sollen, logisch in Blöcke, die in einer hierarchischen Struktur leben. Bei jedem Abfragen einer Client-Abfrage beginnt Nginx einen Prozess zur Feststellung, welche Konfigurationsblöcke zur Bearbeitung der Abfrage verwendet werden sollen. Dieser Entscheidungsprozess ist das, was wir in diesem Leitfaden diskutieren werden.

      Die Hauptblöcke, die wir diskutieren werden, sind der Server-Block und der Standort-Block.

      Ein Serverblock ist eine Teilmenge der Nginx-Konfiguration, die einen virtuellen Server definiert, der zur Verarbeitung von Abfragen eines definierten Typs verwendet wird. Administratoren konfigurieren häufig mehrere Serverblöcke und entscheiden anhand des angeforderten Domainnamens, Ports und der IP-Adresse, welcher Block welche Verbindung verarbeiten soll.

      Ein Standortblock befindet sich in einem Serverblock und wird verwendet, um zu definieren, wie Nginx Abfragen für verschiedene Ressourcen und URIs für den übergeordneten Server verarbeiten soll. Der URI-Bereich kann nach Belieben des Administrators mithilfe dieser Blöcke unterteilt werden. Es ist ein extrem flexibles Modell.

      Wie Nginx entscheidet, welcher Serverblock eine Abfrage verarbeiten wird

      Da der Administrator mit Nginx mehrere Serverblöcke definieren kann, die als separate virtuelle Webserverinstanzen fungieren, muss festgelegt werden, welcher dieser Serverblöcke zur Erfüllung einer Abfrage verwendet wird.

      Dies geschieht durch ein definiertes System von Überprüfungen, mit denen die bestmögliche Übereinstimmung gefunden wird. Die wichtigsten Serverblock-Direktiven, mit denen sich Nginx während dieses Prozesses befasst, sind die Direktive listen und server_name.

      Analysieren der „listen“-Direktive, um mögliche Übereinstimmungen zu finden

      Zunächst überprüft Nginx die IP-Adresse und den Port der Abfrage. Dies wird mit der listen-Direktive jedes Servers verglichen, um eine Liste der Serverblöcke zu erstellen, die möglicherweise die Abfrage auflösen können.

      Die listen-Direktive definiert typischerweise, auf welche IP-Adresse und welchen Port der Serverblock reagieren wird. Standardmäßig erhält jeder Serverblock, der keine listen-Direktive enthält, die listen-Parameter 0.0.0.0:80 (oder 0.0.0.0:8080, wenn Nginx von einem normalen non-root-Benutzer ausgeführt wird). Auf diese Weise können diese Blöcke auf Abfragen an einer beliebigen Schnittstelle an Port 80 antworten, aber dieser Standardwert hat im Serverauswahlprozess nicht viel Gewicht.

      Die listen-Direktive kann auf Folgendes eingestellt werden:

      • Eine Kombination aus IP-Adresse und Port.
      • Eine einzelne IP-Adresse, die dann den Standardport 80 überwacht.
      • Ein einzelner Port, der jede Schnittstelle an diesem Port überwacht.
      • Der Pfad zu einem Unix-Socket.

      Die letzte Option hat im Allgemeinen nur Auswirkungen beim Übergeben von Abfragen zwischen verschiedenen Servern.

      Wenn Sie versuchen, zu bestimmen, an welchen Serverblock eine Abfrage gesendet wird, wird Nginx zunächst versuchen, anhand der Spezifität der listen-Direktive mit den folgenden Regeln zu entscheiden:

      • Nginx übersetzt alle „unvollständigen“ listen-Direktiven, indem fehlende Werte mit den Standardwerten ersetzt werden, sodass jeder Block durch seine IP-Adresse und den Port bewertet werden kann. Einige Beispiele für diese Übersetzungen sind:
        • Ein Block ohne listen-Direktive verwendet den Wert 0.0.0.0:80.
        • Ein Block, der auf eine IP-Adresse 111.111.111.111 ohne Port festgelegt ist, wird zu 111.111.111.111:80
        • Ein Block, der auf Port 8888 ohne IP-Adresse festgelegt ist, wird zu 0.0.0.0:8888
      • Nginx versucht dann, eine Liste der Serverblöcke zu sammeln, die der Abfrage am spezifischsten entsprechen, basierend auf der IP-Adresse und dem Port. Dies bedeutet, dass ein Block, der funktional 0.0.0.0 als IP-Adresse verwendet (um mit einer beliebigen Schnittstelle übereinzustimmen), nicht ausgewählt wird, wenn übereinstimmende Blöcke vorhanden sind, in denen eine bestimmte IP-Adresse aufgeführt ist. In jedem Fall muss der Port genau übereinstimmen.
      • Wenn nur eine spezifischste Übereinstimmung vorhanden ist, wird dieser Serverblock verwendet, um die Abfrage zu bedienen. Wenn mehrere Serverblöcke mit derselben Spezifitätsübereinstimmung vorhanden sind, beginnt Nginx mit der Auswertung der Direktive server_name jedes Serverblocks.

      Es ist wichtig, zu verstehen, dass Nginx die Direktive server_name nur dann auswertet, wenn zwischen Serverblöcken unterschieden werden muss, die der gleichen Spezifitätsstufe in der listen-Direktive entsprechen. Wenn beispielsweise example.com auf Port 80 von 192.168.1.10 gehostet wird, wird eine Abfrage für example.com in diesem Beispiel trotz der Direktive server_name im zweiten Block immer vom ersten Block bedient.

      server {
          listen 192.168.1.10;
      
          . . .
      
      }
      
      server {
          listen 80;
          server_name example.com;
      
          . . .
      
      }
      

      Für den Fall, dass mehr als ein Serverblock mit gleicher Spezifität übereinstimmt, besteht der nächste Schritt darin, die Direktive server_name zu überprüfen.

      Analysieren der Direktive „server_name“, um eine Übereinstimmung auszuwählen

      Um Abfragen mit gleichermaßen spezifischen listen-Direktiven weiter auszuwerten, überprüft Nginx die „Host“-Überschrift der Abfrage. Dieser Wert enthält die Domain oder IP-Adresse, die der Client tatsächlich versucht hat, zu erreichen.

      Nginx versucht, die beste Übereinstimmung für den gefundenen Wert zu finden, indem es sich die Direktive server_name in jedem der Serverblöcke ansieht, die noch Auswahlkandidaten sind. Nginx bewertet diese durch die folgende Formel:

      • Nginx versucht zunächst, einen Serverblock mit einem server_name zu finden, der dem Wert in der „Host“-Überschrift der Abfrage genau entspricht. Wenn dieser gefunden wird, wird der zugeordnete Block verwendet, um die Abfrage zu bedienen. Wenn mehrere genaue Übereinstimmungen gefunden werden, wird die erste verwendet.
      • Wenn keine genaue Übereinstimmung gefunden wird, versucht Nginx, einen Serverblock mit einem server_name zu finden, der mit einem führenden Platzhalter übereinstimmt (angezeigt durch ein * am Anfang des Namens in der Konfiguration). Wenn eine gefunden wird, wird der zugeordnete Block verwendet, um die Abfrage zu bedienen. Wenn mehrere Übereinstimmungen gefunden werden, wird die längste Übereinstimmung verwendet, um die Abfrage zu bedienen.
      • Wenn mit einem führenden Platzhalter keine Übereinstimmung gefunden wird, sucht Nginx nach einem Serverblock mit einem server_name, der mit einem nachfolgenden Platzhalter übereinstimmt (angezeigt durch einen Servernamen, der in der Konfiguration mit einem * endet). Wenn eine gefunden wird, wird dieser Block verwendet, um die Abfrage zu bedienen. Wenn mehrere Übereinstimmungen gefunden werden, wird die längste Übereinstimmung verwendet, um die Abfrage zu bedienen.
      • Wenn mit einem nachgestellten Platzhalter keine Übereinstimmung gefunden wird, wertet Nginx Serverblöcke aus, die den server_name mithilfe regulärer Ausdrücke definieren (angezeigt durch ein ~ vor dem Namen). Der erste server_name mit einem regulären Ausdruck, der der „Host“-Überschrift entspricht, wird zur Bearbeitung der Abfrage verwendet.
      • Wenn keine Übereinstimmung mit regulären Ausdrücken gefunden wird, wählt Nginx den Standardserverblock für diese IP-Adresse und diesen Port aus.

      Jede Kombination aus IP-Adresse und Port verfügt über einen Standardserverblock, der verwendet wird, wenn mit den oben genannten Methoden keine Vorgehensweise festgelegt werden kann. Bei einer Kombination aus IP-Adresse und Port ist dies entweder der erste Block in der Konfiguration oder der Block, der die Option default_server als Teil der listen-Direktive enthält (die den zuerst gefundenen Algorithmus überschreiben würde). Pro IP-Adresse/Port-Kombination kann nur eine default_server-Deklaration vorhanden sein.

      Beispiele

      Wenn ein server_name definiert ist, der genau mit dem „Host“-Überschriftswert übereinstimmt, wird dieser Serverblock ausgewählt, um die Abfrage zu verarbeiten.

      Wenn in diesem Beispiel die „Host“-Überschrift der Abfrage auf „host1.example.com“ gesetzt wäre, würde der zweite Server ausgewählt:

      server {
          listen 80;
          server_name *.example.com;
      
          . . .
      
      }
      
      server {
          listen 80;
          server_name host1.example.com;
      
          . . .
      
      }
      

      Wenn keine genaue Übereinstimmung gefunden wird, prüft Nginx, ob ein server_name mit einem passenden Start-Platzhalter vorhanden ist. Die längste Übereinstimmung mit einem Platzhalter wird ausgewählt, um die Abfrage zu erfüllen.

      Wenn in diesem Beispiel die Abfrage einer „Host“-Überschrift „www.example.org“ hat, würde der zweite Serverblock ausgewählt:

      server {
          listen 80;
          server_name www.example.*;
      
          . . .
      
      }
      
      server {
          listen 80;
          server_name *.example.org;
      
          . . .
      
      }
      
      server {
          listen 80;
          server_name *.org;
      
          . . .
      
      }
      

      Wenn mit einem Start-Platzhalter keine Übereinstimmung gefunden wird, prüft Nginx anhand eines Platzhalters am Ende des Ausdrucks, ob eine Übereinstimmung vorliegt. An diesem Punkt wird die längste Übereinstimmung mit einem Platzhalter ausgewählt, um die Abfrage zu bedienen.

      Wenn beispielsweise die Abfrage eine „Host“-Überschrift auf „www.example.com“ festgelegt hat, wird der dritte Serverblock ausgewählt:

      server {
          listen 80;
          server_name host1.example.com;
      
          . . .
      
      }
      
      server {
          listen 80;
          server_name example.com;
      
          . . .
      
      }
      
      server {
          listen 80;
          server_name www.example.*;
      
          . . .
      
      }
      

      Wenn keine Platzhalterübereinstimmungen gefunden werden können, versucht Nginx, Übereinstimmungen mit den Direktiven server_name zuzuordnen, die reguläre Ausdrücke verwenden. Der erste übereinstimmende reguläre Ausdruck wird ausgewählt, um auf die Abfrage zu antworten.

      Wenn beispielsweise die „Host“-Überschrift der Abfrage auf „www.example.com“ gesetzt ist, wird der zweite Serverblock ausgewählt, um die Abfrage zu erfüllen:

      server {
          listen 80;
          server_name example.com;
      
          . . .
      
      }
      
      server {
          listen 80;
          server_name ~^(www|host1).*.example.com$;
      
          . . .
      
      }
      
      server {
          listen 80;
          server_name ~^(subdomain|set|www|host1).*.example.com$;
      
          . . .
      
      }
      

      Wenn keiner der oben genannten Schritte die Abfrage erfüllen kann, wird die Abfrage an den Standardserver für die übereinstimmende IP-Adresse und den passenden Port weitergeleitet.

      Übereinstimmung von Standortblöcken

      Ähnlich wie bei dem Prozess, mit dem Nginx den Serverblock auswählt, der eine Abfrage verarbeitet, verfügt Nginx auch über einen etablierten Algorithmus zur Entscheidung, welcher Standortblock innerhalb des Servers zur Verarbeitung von Abfragen verwendet werden soll.

      Standortblock-Syntax

      Bevor wir uns damit befassen, wie Nginx entscheidet, welcher Standortblock zur Verarbeitung von Abfragen verwendet werden soll, gehen wir einen Teil der Syntax durch, der möglicherweise in Standortblockdefinitionen angezeigt wird. Standortblöcke befinden sich in Serverblöcken (oder anderen Standortblöcken) und werden verwendet, um zu entscheiden, wie der Abfrage-URI (der Teil der Abfrage, der nach dem Domainnamen oder der IP-Adresse/dem IP-Port kommt) verarbeitet werden soll.

      Standortblöcke haben im Allgemeinen die folgende Form:

      location optional_modifier location_match {
      
          . . .
      
      }
      

      Das oben angezeigte location_match definiert, gegen was Nginx den Abfrage-URI prüfen soll. Das Vorhandensein oder Nichtvorhandensein des Modifikators im obigen Beispiel beeinflusst die Art und Weise, wie der Nginx versucht, mit dem Standortblock übereinzustimmen. Die folgenden Modifikatoren bewirken, dass der zugehörige Standortblock wie folgt interpretiert wird:

      • (none): Wenn keine Modifikatoren vorhanden sind, wird der Speicherort als Präfix-Übereinstimmung interpretiert. Dies bedeutet, dass der angegebene Speicherort mit dem Beginn des Abfrage-URIs abgeglichen wird, um eine Übereinstimmung zu ermitteln.
      • =: Wenn ein Gleichheitszeichen verwendet wird, wird dieser Block als Übereinstimmung betrachtet, wenn der Abfrage-URI genau mit dem angegebenen Standort übereinstimmt.
      • ~: Wenn ein Tilde-Modifikator vorhanden ist, wird dieser Speicherort als Übereinstimmung zwischen regulären Ausdrücken und Groß- und Kleinschreibung interpretiert.
      • ~*: Wenn ein Tilde- und ein Sternchen-Modifikator verwendet werden, wird der Positionsblock als Übereinstimmung zwischen regulären Ausdrücken ohne Berücksichtigung der Groß- und Kleinschreibung interpretiert.
      • ^~: Wenn ein Karat- und Tilde-Modifikator vorhanden ist und dieser Block als beste Übereinstimmung mit nicht regulären Ausdrücken ausgewählt ist, findet keine Übereinstimmung mit regulären Ausdrücken statt.

      Beispiele zur Demonstration der Standortblock-Syntax

      Als Beispiel für die Präfixübereinstimmung kann der folgende Standortblock ausgewählt werden, um auf Abfrage-URIs zu antworten, die wie /site, /site/page1/index.html oder /site/index.html aussehen:

      location /site {
      
          . . .
      
      }
      

      Zur Demonstration der genauen Übereinstimmung der Abfrage-URI wird dieser Block immer verwendet, um auf eine Abfrage-URI zu antworten, die wie /page1 aussieht. Es wird nicht verwendet, um auf eine /page1/index.html-Abfrage-URI zu antworten. Beachten Sie, dass bei Auswahl dieses Blocks und Erfüllung der Abfrage über eine Indexseite eine interne Umleitung an einen anderen Speicherort erfolgt, der der eigentliche Handhaber der Abfrage ist:

      location = /page1 {
      
          . . .
      
      }
      

      Als Beispiel für einen Speicherort, der als regulärer Ausdruck mit Groß- und Kleinschreibung interpretiert werden sollte, kann dieser Block verwendet werden, um Abfragen für /tortoise.jpg zu verarbeiten, nicht jedoch für /FLOWER.PNG:

      location ~ .(jpe?g|png|gif|ico)$ {
      
          . . .
      
      }
      

      Ein Block, der eine Übereinstimmung ohne Berücksichtigung der Groß- und Kleinschreibung ähnlich wie oben ermöglichen würde, ist unten dargestellt. Hier könnten sowohl /tortoise.jpg als auch /FLOWER.PNG von diesem Block verarbeitet werden:

      location ~* .(jpe?g|png|gif|ico)$ {
      
          . . .
      
      }
      

      Schließlich würde dieser Block verhindern, dass eine Übereinstimmung mit regulären Ausdrücken auftritt, wenn festgestellt wird, dass dies die beste Übereinstimmung mit nicht regulären Ausdrücken ist. Er könnte Abfragen für /costumes/ninja.html verarbeiten:

      location ^~ /costumes {
      
          . . .
      
      }
      

      Wie Sie sehen, geben die Modifikatoren an, wie der Standortblock interpretiert werden soll. Dies sagt uns jedoch nicht, welchen Algorithmus Nginx verwendet, um zu entscheiden, an welchen Standortblock die Abfrage gesendet werden soll. Wir werden das als nächstes durchgehen.

      Wie Nginx wählt, welcher Standort zur Bearbeitung von Abfragen verwendet werden soll

      Nginx wählt den Speicherort aus, an dem eine Abfrage bearbeitet wird, ähnlich wie bei der Auswahl eines Serverblocks. Es wird ein Prozess durchlaufen, der den besten Standortblock für eine bestimmte Abfrage ermittelt. Das Verständnis dieses Prozesses ist eine entscheidende Anforderung, um Nginx zuverlässig und korrekt konfigurieren zu können.

      Unter Berücksichtigung der oben beschriebenen Arten von Standortdeklarationen bewertet Nginx die möglichen Standortkontexte, indem der Abfrage-URI mit jedem der Standorte verglichen wird. Dies geschieht mit dem folgenden Algorithmus:

      • Nginx überprüft zunächst alle Präfix-basierten Standortübereinstimmungen (alle Standorttypen, die keinen regulären Ausdruck enthalten). Es vergleicht jeden Standort mit dem vollständigen Abfrage-URI.
      • Zunächst sucht Nginx nach einer genauen Übereinstimmung Wenn ein Standortblock mit dem Modifikator = gefunden wird, der genau mit dem Abfrage-URI übereinstimmt, wird dieser Standortblock sofort ausgewählt, um die Abfrage zu bedienen.
      • Wenn keine genauen (mit dem Modifikator =) Positionsblockübereinstimmungen gefunden werden, fährt Nginx mit der Auswertung nicht exakter Präfixe fort. Es ermittelt den am längsten übereinstimmenden Präfixspeicherort für den angegebenen Abfrage-URI, den es dann wie folgt auswertet:
        • Wenn der am längsten übereinstimmende Präfixstandort den Modifikator ^ ~ hat, beendet Nginx die Suche sofort und wählt diesen Standort aus, um die Abfrage zu bearbeiten.
        • Wenn die Position mit dem längsten übereinstimmenden Präfix nicht den Modifikator ^ ~ verwendet, wird die Übereinstimmung für den Moment von Nginx gespeichert, damit der Fokus der Suche verschoben werden kann.
      • Nachdem die Position mit der längsten Übereinstimmung ermittelt und gespeichert wurde, fährt Nginx mit der Auswertung der Positionen für reguläre Ausdrücke fort (sowohl Groß- und Kleinschreibung als auch Nicht-Groß-/Kleinschreibung beachten). Wenn sich Positionen mit regulären Ausdrücken innerhalb der am längsten übereinstimmenden Präfixposition befinden, verschiebt Nginx diese an den Anfang der Liste der zu überprüfenden Regex-Positionen. Nginx versucht dann, nacheinander mit den Positionen der regulären Ausdrücke abzugleichen. Der erste reguläre Ausdruck des Standortes wird sofort ausgewählt, um die Abfrage zu bedienen.
      • Wenn keine Standorte für reguläre Ausdrücke gefunden werden, die mit dem Abfrage-URI übereinstimmen, wird der zuvor gespeicherte Präfixstandort ausgewählt, um die Abfrage zu bedienen.

      Es ist wichtig, zu verstehen, dass Nginx standardmäßig Übereinstimmungen mit regulären Ausdrücken anstelle von Präfixübereinstimmungen bereitstellt. Es werden jedoch zuerst Präfixpositionen ausgewertet, sodass die Verwaltung diese Tendenz überschreiben kann, indPositionen mit den Modifikatoren = und ^ ~ angegeben werden.

      Es ist auch wichtig, zu beachten, dass, während Präfixpositionen im Allgemeinen basierend auf der längsten, spezifischsten Übereinstimmung ausgewählt werden, die Auswertung regulärer Ausdrücke gestoppt wird, wenn die erste übereinstimmende Position gefunden wird. Dies bedeutet, dass die Positionierung innerhalb der Konfiguration enorme Auswirkungen auf die Positionen regulärer Ausdrücke hat.

      Schließlich ist es wichtig, zu verstehen, dass Übereinstimmungen mit regulären Ausdrücken innerhalb der längsten Präfixübereinstimmung „die Zeile überspringen“, wenn Nginx Regex-Positionen auswertet. Diese werden der Reihe nach ausgewertet, bevor andere Übereinstimmungen mit regulären Ausdrücken berücksichtigt werden. Maxim Dounin, ein unglaublich hilfreicher Nginx-Entwickler, erklärt in diesem Beitrag diesen Teil des Auswahlalgorithmus.

      Wann springt die Standortblockbewertung zu anderen Standorten?

      Wenn ein Standortblock ausgewählt wird, um eine Abfrage zu bedienen, wird die Abfrage im Allgemeinen von diesem Punkt an vollständig in diesem Kontext behandelt. Nur der ausgewählte Standort und die geerbten Anweisungen bestimmen, wie die Abfrage verarbeitet wird, ohne dass Geschwisterstandortblöcke eingreifen.

      Obwohl dies eine allgemeine Regel ist, mit der Sie Ihre Standortblöcke auf vorhersehbare Weise entwerfen können, ist es wichtig zu wissen, dass es manchmal Zeiten gibt, in denen eine neue Standortsuche durch bestimmte Anweisungen innerhalb des ausgewählten Standortes ausgelöst wird. Die Ausnahmen von der Regel „Nur ein Standortblock“ können Auswirkungen auf die tatsächliche Zustellung der Abfrage haben und stimmen möglicherweise nicht mit den Erwartungen überein, die Sie beim Entwerfen Ihrer Standortblöcke hatten.

      Einige Direktiven, die zu dieser Art der internen Weiterleitung führen können, sind:

      • index
      • try_files
      • rewrite
      • error_page

      Gehen wir diese kurz durch.

      Die Direktive index führt immer zu einer internen Weiterleitung, wenn sie verwendet wird, um die Abfrage zu verarbeiten. Genaue Standortübereinstimmungen werden häufig verwendet, um den Auswahlprozess zu beschleunigen, indem die Ausführung des Algorithmus sofort beendet wird. Wenn Sie jedoch eine genaue Standortübereinstimmung mit einem Verzeichnis vornehmen, besteht eine gute Chance, dass die Abfrage zur tatsächlichen Verarbeitung an einen anderen Standort umgeleitet wird.

      In diesem Beispiel wird der erste Standort mit einem Abfrage-URI von /exact abgeglichen. Um die Abfrage zu verarbeiten, initiiert die vom Block geerbte Indexanweisung eine interne Umleitung zum zweiten Block:

      index index.html;
      
      location = /exact {
      
          . . .
      
      }
      
      location / {
      
          . . .
      
      }
      

      Wenn Sie im obigen Fall wirklich die Ausführung benötigen, um im ersten Block zu bleiben, müssen Sie eine andere Methode finden, um die Abfrage an das Verzeichnis zu erfüllen. Sie können beispielsweise einen ungültigen index für diesen Block festlegen und den autoindex aktivieren:

      location = /exact {
          index nothing_will_match;
          autoindex on;
      }
      
      location  / {
      
          . . .
      
      }
      

      Dies ist eine Möglichkeit, um zu verhindern, dass ein index den Kontext wechselt, ist jedoch für die meisten Konfigurationen wahrscheinlich nicht hilfreich. Meistens kann eine genaue Übereinstimmung mit Verzeichnissen hilfreich sein, um beispielsweise die Abfrage neu zu schreiben (was auch zu einer neuen Standortsuche führt).

      Eine andere Instanz, in der der Verarbeitungsort neu bewertet werden kann, ist die Direktive try_files. Diese Direktive weist Nginx an, das Vorhandensein einer benannten Gruppe von Dateien oder Verzeichnissen zu überprüfen. Der letzte Parameter kann ein URI sein, zu dem Nginx eine interne Umleitung vornimmt.

      Erwägen Sie folgende Konfiguration:

      root /var/www/main;
      location / {
          try_files $uri $uri.html $uri/ /fallback/index.html;
      }
      
      location /fallback {
          root /var/www/another;
      }
      

      Wenn im obigen Beispiel eine Anfrage für /blahblah gestellt wird, erhält der erste Standort zunächst die Abfrage. Er wird versuchen, eine Datei namens blahblah im Verzeichnis /var/www/main zu finden. Wenn gefunden werden kann, wird anschließend nach einer Datei mit dem Namen blahblah.html gesucht. Anschließend wird versucht, festzustellen, ob sich im Verzeichnis /var/www/main ein Verzeichnis mit dem Namen blahblah/ befindet. Wenn alle diese Versuche fehlschlagen, wird zu /fallback/index.html umgeleitet. Dies löst eine weitere Standortsuche aus, die vom zweiten Standortblock abgefangen wird. Dies wird die Datei /var/www/anderen/fallback/index.html bereitstellen.

      Eine weitere Direktive, die dazu führen kann, dass ein Standortblock übergeben wird, ist die Direktive rewrite. Wenn Sie den letzten Parameter mit der Direktive rewrite zum Umschreiben oder überhaupt keinen Parameter verwenden, sucht Nginx basierend auf den Ergebnissen des Umschreibens nach einem neuen übereinstimmenden Standort.

      Wenn wir beispielsweise das letzte Beispiel so ändern, dass es ein Umschreiben enthält, können wir feststellen, dass die Abfrage manchmal direkt an den zweiten Standort übergeben wird, ohne sich auf die Direktive try_files zu verlassen:

      root /var/www/main;
      location / {
          rewrite ^/rewriteme/(.*)$ /$1 last;
          try_files $uri $uri.html $uri/ /fallback/index.html;
      }
      
      location /fallback {
          root /var/www/another;
      }
      

      Im obigen Beispiel wird eine Abfrage für /rewriteme/hello zunächst vom ersten Standortblock verarbeitet. Sie wird in /hello umgeschrieben und ein Standort gesucht. In diesem Fall stimmt sie wieder mit dem ersten Standort überein und wird wie gewohnt von den try_files verarbeitet. Wenn nichts gefunden wird, kehren Sie möglicherweise zu /fallback/index.html zurück (mithilfe der oben beschriebenen internen Umleitung try_files).

      Wenn jedoch eine Abfrage für /rewriteme/fallback/hello gestellt wird, stimmt der erste Block erneut überein. Das Umschreiben wird erneut angewendet, diesmal mit /fallback/hello. Die Abfrage wird dann aus dem zweiten Standortblock heraus zugestellt.

      Eine verwandte Situation tritt bei der Direktive return auf, wenn die Statuscodes 301 oder 302 gesendet werden. Der Unterschied in diesem Fall ist, dass es eine völlig neue Abfrage in Form einer extern sichtbaren Umleitung bildet. Dieselbe Situation kann bei der Direktive rewrite auftreten, wenn die Flags redirect oder permanent verwendet werden. Diese Standortsuche sollte jedoch nicht unerwartet sein, da extern sichtbare Weiterleitungen immer zu einer neuen Abfrage führen.

      Die Direktive error_page kann zu einer internen Umleitung führen, die der von try_files erstellten ähnelt. Diese Direktive wird verwendet, um zu definieren, was passieren soll, wenn bestimmte Statuscodes aufgetreten sind. Dies wird wahrscheinlich nie ausgeführt, wenn try_files festgelegt ist, da diese Direktive den gesamten Lebenszyklus einer Abfrage behandelt.

      Erwägen Sie dieses Beispiel:

      root /var/www/main;
      
      location / {
          error_page 404 /another/whoops.html;
      }
      
      location /another {
          root /var/www;
      }
      

      Jede Abfrage (außer denjenigen, die mit /another beginnen) wird vom ersten Block bearbeitet, der Dateien aus /var/www/main bereitstellt. Wenn jedoch keine Datei gefunden wird (Status 404), erfolgt eine interne Umleitung zu /another/whoops.html, die zu einer neuen Standortsuche führt, die schließlich im zweiten Block landet. Diese Datei wird aus /var/www/another/whoops.html. bereitgestellt.

      Wie Sie sehen können, kann das Verständnis der Umstände, unter denen Nginx eine neue Standortsuche auslöst, dazu beitragen, das Verhalten vorherzusagen, das bei Abfragen auftreten wird.

      Zusammenfassung

      Wenn Sie wissen, wie Nginx Client-Abfragen verarbeitet, können Sie Ihre Arbeit als Administrator erheblich vereinfachen. Sie können anhand jeder Client-Abfrage wissen, welchen Serverblock Nginx auswählt. Sie können auch anhand der Abfrage-URI festlegen, wie der Standortblock ausgewählt wird. Wenn Sie wissen, wie Nginx verschiedene Blöcke auswählt, können Sie die Kontexte verfolgen, die Nginx anwenden wird, um jede Abfrage zu bearbeiten.



      Source link

      Información sobre algoritmos de selección de bloques de servidores y ubicación de Nginx


      Introducción

      Nginx es uno de los servidores web más populares del mundo. Puede manejar correctamente altas cargas con muchas conexiones de clientes concurrentes y puede funcionar fácilmente como servidor web, servidor de correo o servidor de proxy inverso.

      En esta guía, explicaremos algunos de los detalles en segundo plano que determinan cómo Nginx procesa las solicitudes de los clientes. Entender estas ideas puede ayudar a despejar las incógnitas sobre el diseño de bloques de servidores y ubicación, y puede hacer que el manejo de las solicitudes parezca menos impredecible.

      Configuraciones de bloques de Nginx

      Nginx divide de forma lógica las configuraciones destinadas a entregar distintos contenidos en bloques, que conviven en una estructura jerárquica. Cada vez que se realiza una solicitud de cliente, Nginx inicia un proceso para determinar qué bloques de configuración deben usarse para gestionar la solicitud. Este proceso de decisión es lo que explicaremos en esta guía.

      Los bloques principales que explicaremos son el bloque de servidor y el bloque de ubicación.

      Un bloque de servidor es un subconjunto de la configuración de Nginx que define un servidor virtual utilizado para gestionar las solicitudes de un tipo definido. Los administradores suelen configurar varios bloques de servidores y decidir qué bloque debe gestionar cada conexión según el nombre de dominio, el puerto y la dirección IP solicitados.

      Un bloque de ubicación reside dentro de un bloque de servidor y se utiliza para definir la manera en que Nginx debe gestionar las solicitudes para diferentes recursos y URI para el servidor principal. El espacio URI puede subdividirse de la manera que el administrador quiera utilizando estos bloques. Es un modelo extremadamente flexible.

      Cómo decide Nginx qué bloque de servidor gestionará una solicitud

      Dado que Nginx permite que el administrador defina varios bloques de servidores que funcionan como instancias de servidores web virtuales independientes, necesita un procedimiento para determinar cuál de estos bloques de servidores se utilizará para satisfacer una solicitud.

      Lo hace mediante un sistema definido de comprobaciones que se utilizan para encontrar la mejor coincidencia posible. Las principales directivas de bloques de servidores de las que se ocupa Nginx durante este proceso son la directiva listen y la directiva server_name.

      Análisis de la directiva “listen” para encontrar posibles coincidencias

      Primero, Nginx examina la dirección IP y el puerto de la solicitud. Luego, lo compara con la directiva listen de cada servidor para crear una lista de los bloques de servidores que pueden resolver la solicitud.

      La directiva listen generalmente define la dirección IP y el puerto a los que responderá el bloque de servidor. De manera predeterminada, cualquier bloque de servidor que no incluya una directiva listen recibe los parámetros de escucha 0.0.0.0:80 (o 0.0.0.0:8080 si Nginx está siendo ejecutado por un usuario no root regular). Eso permite que estos bloques respondan a las solicitudes en cualquier interfaz en el puerto 80, pero este valor predeterminado no afecta demasiado al proceso de selección de servidores.

      La directiva listen puede establecerse para las siguientes características:

      • Una combinación de dirección IP y puerto.
      • Una dirección IP individual que escuchará en el puerto 80 de manera predeterminada.
      • Un puerto individual que escuchará cada interfaz en ese puerto.
      • La ruta al socket Unix.

      La última opción, por lo general, solo tendrá implicaciones al pasar solicitudes entre distintos servidores.

      Cuando intente determinar a qué bloque de servidor enviar una solicitud, Nginx tratará primero de decidir según la especificidad de la directiva listen usando las siguientes reglas:

      • Nginx traduce todas las directivas listen “incompletas” sustituyendo los valores que faltan por sus valores predeterminados para que cada bloque pueda evaluarse por su dirección IP y su puerto. Algunos ejemplos de estas traslaciones son:
        • Un bloque sin directiva listen utiliza el valor 0.0.0.0:80.
        • Un bloque establecido en una dirección IP 111.111.111.111 sin puerto se convierte en 111.111.111.111:80.
        • Un bloque establecido en el puerto 8888 sin dirección IP se convierte en 0.0.0.0:8888.
      • Luego, Nginx intenta recopilar una lista de los bloques de servidores que coinciden con la solicitud más específicamente basada en la dirección IP y el puerto. Eso significa que cualquier bloque que esté usando de forma funcional 0.0.0.0 como su dirección IP (para coincidir con cualquier interfaz), no se seleccionará si hay bloques coincidentes que enumeran una dirección IP específica. En todo caso, el puerto debe coincidir con exactitud.
      • Si solo hay una coincidencia más específica, ese bloque de servidor se utilizará para atender la solicitud. Si hay varios bloques de servidores con el mismo nivel de coincidencia de especificidad, Nginx comienza a evaluar la directiva server_name de cada bloque de servidores.

      Es importante entender que Nginx solo evaluará la directiva server_name cuando necesite distinguir entre bloques de servidores que coinciden con el mismo nivel de especificidad en la directiva listen. Por ejemplo, si example.com está alojado en el puerto 80 de 192.168.1.10, una solicitud para example.com siempre será atendida por el primer bloque de este ejemplo, a pesar de la directiva server_name en el segundo bloque.

      server {
          listen 192.168.1.10;
      
          . . .
      
      }
      
      server {
          listen 80;
          server_name example.com;
      
          . . .
      
      }
      

      En caso de que más de un bloque de servidor coincida con la misma especificidad, el siguiente paso es verificar la directiva server_name.

      Análisis de la directiva “server_name” para elegir una coincidencia

      Luego, para evaluar más a fondo las solicitudes que tienen directivas listen igualmente específicas, Nginx verifica el encabezado “Host” de la solicitud. Ese valor contiene el dominio o la dirección IP que el cliente estaba intentando alcanzar.

      Nginx intenta encontrar la mejor coincidencia para el valor que encuentra al ver la directiva server_name dentro de cada uno de los bloques de servidores que aún son candidatos a selección. Nginx lo evalúa usando la siguiente formula:

      • Nginx intentará primero encontrar un bloque de servidor con un server_name que coincida con el valor en el encabezado “Host” de la solicitud de manera exacta. Si lo encuentra, ese bloque asociado se utilizará para atender la solicitud. Si se encuentran varias coincidencias exactas, se utiliza la primera coincidencia.
      • Si no se encuentra ninguna coincidencia exacta, Nginx intentará encontrar un bloque de servidor con un server_name que coincida usando un comodín inicial (indicado por un * al principio del nombre en la configuración). Si lo encuentra, ese bloque se utilizará para atender la solicitud. Si se encuentran varias coincidencias, la coincidencia más larga se utilizará para atender la solicitud.
      • Si no se encuentra ninguna coincidencia con el comodín inicial, Nginx buscará entonces un bloque de servidor con un server_name que coincida usando un comodín final (indicado por un nombre de servidor que termina con un * en la configuración). Si lo encuentra, ese bloque se utilizará para atender la solicitud. Si se encuentran varias coincidencias, la coincidencia más larga se utilizará para atender la solicitud.
      • Si no se encuentra ninguna coincidencia usando un comodín final, Nginx evalúa los bloques de servidor que definen el server_name usando expresiones regulares (indicadas por un ~ antes del nombre). El primer server_name con una expresión regular que coincida con el encabezado “Host” se utilizará para atender la solicitud.
      • Si no se encuentra ninguna coincidencia de expresión regular, Nginx selecciona el bloque de servidor predeterminado para esa dirección IP y ese puerto.

      Cada combinación de dirección IP/puerto tiene un bloque de servidor predeterminado que se utilizará cuando no se pueda determinar un curso de acción con los métodos anteriores. En el caso de una combinación de dirección IP y puerto, será el primer bloque de la configuración o el bloque que contiene la opción default_server como parte de la directiva listen (que anularía el primer algoritmo encontrado). Solo puede haber una declaración default_server por cada combinación de dirección IP y puerto.

      Ejemplos

      Si se define un server_name que coincida exactamente con el valor de encabezado “Host”, se selecciona ese bloque de servidor para procesar la solicitud.

      En este ejemplo, si el encabezado “Host” de la solicitud se estableció en “host1.example.com”, se seleccionaría el segundo servidor:

      server {
          listen 80;
          server_name *.example.com;
      
          . . .
      
      }
      
      server {
          listen 80;
          server_name host1.example.com;
      
          . . .
      
      }
      

      Si no se encuentra ninguna coincidencia exacta, Nginx comprueba entonces si hay un server_name con un comodín inicial que coincida. Se seleccionará la coincidencia más larga que comience con un comodín para satisfacer la solicitud.

      En este ejemplo, si la solicitud tuviera un encabezado “Host” de “www.example.org”, se seleccionaría el segundo bloque de servidor:

      server {
          listen 80;
          server_name www.example.*;
      
          . . .
      
      }
      
      server {
          listen 80;
          server_name *.example.org;
      
          . . .
      
      }
      
      server {
          listen 80;
          server_name *.org;
      
          . . .
      
      }
      

      Si no se encuentra ninguna coincidencia con un comodín inicial, Nginx verá si existe una coincidencia usando un comodín al final de la expresión. En este punto, se seleccionará la coincidencia más larga que termine con un comodín para atender la solicitud.

      Por ejemplo, si la solicitud tiene un encabezado “Host” establecido en “www.example.com”, se seleccionará el tercer bloque de servidor:

      server {
          listen 80;
          server_name host1.example.com;
      
          . . .
      
      }
      
      server {
          listen 80;
          server_name example.com;
      
          . . .
      
      }
      
      server {
          listen 80;
          server_name www.example.*;
      
          . . .
      
      }
      

      Si no se encuentran coincidencias con los comodines, Nginx pasará a intentar coincidir con las directivas server_name que utilicen expresiones regulares. Se seleccionará la primera expresión regular que coincida para responder a la solicitud.

      Por ejemplo, si el encabezado “Host” de la solicitud está configurado en “www.example.com”, se seleccionará el segundo bloque de servidor para satisfacer la solicitud:

      server {
          listen 80;
          server_name example.com;
      
          . . .
      
      }
      
      server {
          listen 80;
          server_name ~^(www|host1).*.example.com$;
      
          . . .
      
      }
      
      server {
          listen 80;
          server_name ~^(subdomain|set|www|host1).*.example.com$;
      
          . . .
      
      }
      

      Si ninguno de los pasos anteriores puede satisfacer la solicitud, la solicitud se pasará al servidor predeterminado para la dirección IP y el puerto que coincidan.

      Bloques de ubicación que coinciden

      De forma similar al proceso que utiliza Nginx para seleccionar el bloque del servidor que procesará una solicitud, Nginx también tiene un algoritmo establecido para decidir qué bloque de ubicación dentro del servidor se utilizará para gestionar las solicitudes.

      Sintaxis de bloques de ubicación

      Antes de ver cómo Nginx decide qué bloque de ubicación utilizar para gestionar las solicitudes, repasemos parte de la sintaxis que se podría encontrar en las definiciones de los bloques de ubicación. Los bloques de ubicación se encuentran dentro de los bloques de servidor (u otros bloques de ubicación) y se utilizan para decidir cómo procesar la URI de la solicitud (la parte de la solicitud que viene después del nombre de dominio o la dirección IP/puerto).

      Los bloques de ubicación generalmente tienen la siguiente forma:

      location optional_modifier location_match {
      
          . . .
      
      }
      

      location_match que aparece arriba define contra qué debe comprobar Nginx la URI de la solicitud. La existencia o la inexistencia del modificador en el ejemplo anterior afecta a la forma en que Nginx intenta hacer coincidir el bloque de ubicación. Los modificadores que se muestran abajo harán que el bloque de ubicación asociado se interprete de la siguiente manera:

      • (none): si no hay modificadores, la ubicación se interpreta como una coincidencia de prefijo. Eso significa que la ubicación dada coincidirá con el principio del URI de la solicitud para determinar una coincidencia.
      • =: si se utiliza un signo igual, este bloque se considerará coincidente si el URI de la solicitud coincide exactamente con la ubicación indicada.
      • ~: si hay una tilde de la eñe, esta ubicación se interpretará como una coincidencia de expresión regular que distingue entre mayúsculas y minúsculas.
      • ~*: si se utiliza un modificador de tilde de la eñe y asterisco, el bloque de ubicación se interpretará como una coincidencia de expresión regular que no distingue entre mayúsculas y minúsculas.
      • ^~: si hay un modificador de acento circunflejo y tilde de la eñe, y si este bloque se selecciona como la mejor coincidencia de expresión no regular, no se realizará la coincidencia de expresión regular.

      Ejemplos que demuestran la sintaxis del bloque de ubicación

      Como ejemplo de concordancia de prefijos, se puede seleccionar el siguiente bloque de ubicación para responder a los URI de solicitud que tienen el aspecto /site, /site/page1/index.html o /site/index.html:

      location /site {
      
          . . .
      
      }
      

      Para una demostración de la coincidencia exacta del URI de la solicitud, este bloque siempre se utilizará para responder a un URI de solicitud que tenga el aspecto /page1. No se utilizará para responder a un URI de solicitud /page1/index.html. Tenga en cuenta que, si se selecciona este bloque y la solicitud se cumple usando una página de índice, se realizará un redireccionamiento interno a otra ubicación que será la que realmente gestione la solicitud:

      location = /page1 {
      
          . . .
      
      }
      

      Como ejemplo de una ubicación que debe interpretarse como una expresión regular que distingue entre mayúsculas y minúsculas, este bloque puede usarse para gestionar las solicitudes de /tortoise.jpg, pero no para /FLOWER.PNG:

      location ~ .(jpe?g|png|gif|ico)$ {
      
          . . .
      
      }
      

      A continuación, se muestra un bloque que permitiría una coincidencia sin distinción ente mayúsculas y minúsculas similar al que se mostró anteriormente. Este bloque podría gestionar /tortoise.jpg y /FLOWER.PNG:

      location ~* .(jpe?g|png|gif|ico)$ {
      
          . . .
      
      }
      

      Por último, este bloque evitaría que se produjera una coincidencia de expresión regular si se determina que es la mejor coincidencia de expresión no regular. Podría gestionar las solicitudes de /costumes/ninja.html:

      location ^~ /costumes {
      
          . . .
      
      }
      

      Como ve, los modificadores indican cómo debe interpretarse el bloque de ubicación. Sin embargo, esto no nos indica el algoritmo que utiliza Nginx para decidir a qué bloque de ubicación enviar la solicitud. Lo repasaremos a continuación.

      Cómo elige Nginx qué ubicación utilizar para gestionar las solicitudes

      Nginx elige la ubicación que se utilizará para atender una solicitud de forma similar a cómo selecciona un bloque de servidor. Se ejecuta a través de un proceso que determina el mejor bloque de ubicación para cualquier solicitud. Entender este proceso es un requisito crucial para poder configurar Nginx de forma fiable y precisa.

      Teniendo en cuenta los tipos de declaraciones de ubicación que hemos descrito anteriormente, Nginx evalúa los posibles contextos de ubicación comparando el URI de solicitud con cada una de las ubicaciones. Lo hace mediante el siguiente algoritmo:

      • Nginx comienza comprobando todas las coincidencias de ubicación basadas en prefijos (todos los tipos de ubicación que no implican una expresión regular). Comprueba cada ubicación con el URI completo de la solicitud.
      • Primero, Nginx busca una coincidencia exacta. Si se encuentra un bloque de ubicación que utilice el modificador = y que coincida con el URI de la solicitud de manera exacta, este bloque de ubicación se selecciona inmediatamente para atender la solicitud.
      • Si no se encuentran coincidencias exactas con bloques de ubicación (con el modificador =), Nginx pasa a evaluar los prefijos no exactos. Descubre la ubicación del prefijo más largo que coincide con el URI de la solicitud dada que luego evalúa de la siguiente manera:
        • Si la ubicación del prefijo más largo que coincide tiene el modificador ^~, Nginx finalizará inmediatamente su búsqueda y seleccionará esta ubicación para atender la solicitud.
        • Si la ubicación del prefijo más largo que coincide no utiliza el modificador ^~, Nginx almacena la coincidencia de momento para poder cambiar el enfoque de la búsqueda.
      • Una vez que se determina y almacena la ubicación del prefijo más largo que coincide, Nginx procede a evaluar las ubicaciones de expresiones regulares (las que distinguen entre mayúsculas y minúsculas, y las que no). Si hay alguna ubicación de expresiones regulares dentro de la ubicación del prefijo más largo que coincide, Nginx la pondrá a la parte superior de su lista de ubicaciones de regex para comprobar. Luego, Nginx intentará hacer coincidir con las ubicaciones de expresiones regulares de forma secuencial. La primera ubicación de expresión regular que coincida con el URI de la solicitud se seleccionará inmediatamente para atender la solicitud.
      • Si no se encuentra ninguna ubicación de expresión regular que coincida con el URI de la solicitud, se seleccionará la ubicación de prefijo previamente almacenado para atender la solicitud.

      Es importante entender que, de manera predeterminada, Nginx atenderá las coincidencias de expresiones regulares con mayor preferencia en comparación con las coincidencias de prefijos. Sin embargo, primero evalúa las ubicaciones de prefijos, lo que permite al administrador anular esta tendencia especificando las ubicaciones usando los modificadores = y ^~.

      También es importante tener en cuenta que, aunque las ubicaciones de prefijos generalmente se seleccionan según la coincidencia más larga y específica, la evaluación de la expresión regular se detiene cuando se encuentra la primera ubicación que coincida. Eso significa que el posicionamiento dentro de la configuración tiene amplias implicaciones para las ubicaciones de expresiones regulares.

      Por último, es importante entender que las coincidencias de expresiones regulares dentro de la coincidencia del prefijo más largo “saltarán la línea” cuando Nginx evalúe las ubicaciones de regex. Estas se evaluarán en orden, antes de que se consideren las demás coincidencias de expresiones regulares. Maxim Dounin, un desarrollador de Nginx increíblemente atento, explica en esta publicación esta parte del algoritmo de selección.

      ¿Cuándo salta la evaluación del bloque de ubicaciones a otras ubicaciones?

      En general, cuando se selecciona un bloque de ubicación para atender una solicitud, la solicitud se gestiona completamente dentro de ese contexto a partir de ese momento. Solo la ubicación seleccionada y las directivas heredadas determinan cómo se procesa la solicitud, sin interferencia de los bloques de ubicación hermanos.

      Aunque esta es una regla general que le permitirá diseñar sus bloques de ubicación de una manera predecible, es importante darse cuenta de que, a veces, una nueva búsqueda de ubicación se activa por ciertas directivas dentro de la ubicación seleccionada. Las excepciones a la regla “solo un bloque de ubicación” pueden tener implicaciones sobre cómo se atiende realmente la solicitud y pueden no coincidir con las expectativas que tenía al diseñar sus bloques de ubicación.

      Algunas directivas que pueden dar como resultado este tipo de redireccionamiento interno son:

      • index
      • try_files
      • rewrite
      • error_page

      Las repasaremos brevemente.

      La directiva index siempre conduce a un redireccionamiento interno si se utiliza para gestionar la solicitud. Las coincidencias de ubicación exactas se utilizan a menudo para acelerar el proceso de selección, terminando inmediatamente la ejecución del algoritmo. Sin embargo, si realiza una coincidencia de ubicación exacta que sea un directorio, hay una buena probabilidad de que la solicitud sea redirigida a una ubicación diferente para el procesamiento real.

      En este ejemplo, la primera ubicación coincide con un URI de solicitud de /exact, pero, para gestionar la solicitud, la directiva index heredada por el bloque inicia un redireccionamiento interno al segundo bloque:

      index index.html;
      
      location = /exact {
      
          . . .
      
      }
      
      location / {
      
          . . .
      
      }
      

      En el caso anterior, si realmente necesita que la ejecución permanezca en el primer bloque, tendrá que encontrar un método diferente para satisfacer la solicitud al directorio. Por ejemplo, podría establecer un index no válido para ese bloque y activar autoindex:

      location = /exact {
          index nothing_will_match;
          autoindex on;
      }
      
      location  / {
      
          . . .
      
      }
      

      Esta es una forma de evitar que un index cambie de contexto, pero probablemente no sea útil para la mayoría de las configuraciones. Generalmente, una coincidencia exacta en directorios puede ser útil para acciones como reescribir la solicitud (lo que también genera una nueva búsqueda de ubicación).

      Otro caso en que se puede reevaluar la ubicación del procesamiento es con la directiva try_files. Esa directiva le indica a Nginx que busque la existencia de un conjunto determinado de archivos o directorios. El último parámetro puede ser un URI al que Nginx realizará un redireccionamiento interno.

      Analice la siguiente configuración:

      root /var/www/main;
      location / {
          try_files $uri $uri.html $uri/ /fallback/index.html;
      }
      
      location /fallback {
          root /var/www/another;
      }
      

      En el ejemplo anterior, si se realiza una solicitud para /blahblah, la primera ubicación obtendrá inicialmente la solicitud. Intentará encontrar un archivo llamado blahblah en el directorio /var/www/main. Si no puede encontrar ninguno, procederá a buscar un archivo llamado blahblah.html. Luego, intentará buscar un directorio llamado blahblah/ dentro del directorio /var/www/main. Si todos esos intentos fallan, se redirigirá a /fallback/index.html. Eso activará otra búsqueda de ubicación que el segundo bloque de ubicación capturará. Y atenderá el archivo /var/www/another/fallback/index.html.

      Otra directiva que puede pasar el bloque de ubicación es la directiva rewrite. Cuando utiliza el último parámetro con la directiva rewrite o cuando no utiliza ningún parámetro, Nginx buscará una nueva ubicación que coincida según los resultados de la reescritura.

      Por ejemplo, si modificamos el último ejemplo para incluir una reescritura, podemos ver que la solicitud a veces se pasa directamente a la segunda ubicación sin depender de la directiva try_files:

      root /var/www/main;
      location / {
          rewrite ^/rewriteme/(.*)$ /$1 last;
          try_files $uri $uri.html $uri/ /fallback/index.html;
      }
      
      location /fallback {
          root /var/www/another;
      }
      

      En el ejemplo de arriba, el primer bloque de ubicación gestionará inicialmente una solicitud de /rewriteme/hello. Se reescribirá a /hello y se buscará una ubicación. En este caso, volverá a coincidir con la primera ubicación y se procesará mediante try_files de manera habitual, probablemente regresando a /fallback/index.html si no se encuentra nada (usando el redireccionamiento interno de try_files que mencionamos antes).

      Sin embargo, si se realiza una solicitud para /rewriteme/fallback/hello, el primer bloque volverá a coincidir. Se aplicará la reescritura de nuevo, dando como resultado /fallback/hello esta vez. La solicitud se atenderá desde el segundo bloque de ubicación.

      Algo similar sucede con la directiva return cuando se envían los códigos de estado 301 o 302. La diferencia en este caso es que da como resultado una solicitud completamente nueva en forma de un redireccionamiento visible desde el exterior. Eso mismo puede suceder con la directiva rewrite cuando se utilizan los indicadores redirect o permanent. Sin embargo, estas búsquedas de ubicación no deberían ser inesperadas, ya que los redireccionamientos visibles externamente siempre dan como resultado una nueva solicitud.

      La directiva error_page puede dar como resultado un redireccionamiento interno similar al que se creó con try_files. Esa directiva se utiliza para definir lo que debe suceder cuando se encuentran ciertos códigos de estado. Esto probablemente nunca se ejecutará si se establece try_files, ya que esa directiva maneja todo el ciclo de vida de una solicitud.

      Analice este ejemplo:

      root /var/www/main;
      
      location / {
          error_page 404 /another/whoops.html;
      }
      
      location /another {
          root /var/www;
      }
      

      Todas las solicitudes (aparte de las que comienzan con /another) se gestionarán mediante el primer bloque, que atenderá archivos desde /var/www/main. Sin embargo, si no se encuentra un archivo (un estado 404), se producirá un redireccionamiento interno a /another/whoops.html, lo que llevará a una nueva búsqueda de ubicación que finalmente aterrizará en el segundo bloque. Este archivo se atenderá desde /var/www/another/whoops.html.

      Como se puede ver, entender las circunstancias en que Nginx activa una nueva búsqueda de ubicación puede ayudar a predecir el comportamiento que habrá cuando se hagan solicitudes.

      Conclusión

      Entender las formas en que Nginx procesa las solicitudes de los clientes puede hacer que su trabajo como administrador sea mucho más fácil. Podrá saber qué bloque de servidor seleccionará Nginx según cada solicitud del cliente. También podrá saber cómo se seleccionará el bloque de ubicación según el URI de la solicitud. En general, saber la forma en que Nginx selecciona los diferentes bloques le permitirá rastrear los contextos que Nginx aplicará para atender cada solicitud.



      Source link

      Comprendre le serveur Nginx et les algorithmes de sélection de blocs de localisation


      Introduction

      Nginx fait partie des serveurs Web les plus populaires au monde. C’est avec succès qu’il peut gérer de grandes charges avec plusieurs connexions clients concurrentes et être facilement utilisé comme un serveur web, un serveur de courrier ou un serveur proxy inverse.

      Dans ce guide, nous allons traiter de quelques-uns des détails en coulisses qui déterminent la manière dont Nginx traite les requêtes clients. En ayant une compréhension de ces idées, vous n’aurez plus à faire autant de devinettes quant à la conception du serveur et des blocs de localisation et vous serez alors en mesure de rendre la manipulation des requêtes moins imprévisible.

      Configurations de bloc Nginx

      Nginx divise de manière logique les configurations destinées à servir différents contenus dans des blocs qui se trouvent dans une structure hiérarchique. Chaque fois qu’un client fait une requête, Nginx entame un processus pour sélectionner les blocs de configuration qui seront utilisés pour gérer la requête. C’est ce processus de décision que nous allons aborder dans ce guide.

      Les principaux blocs que nous allons aborder sont les suivants : le bloc server et le bloc location.

      Un bloc de serveur est un sous-ensemble de la configuration de Nginx qui définit le serveur virtuel avec lequel les requêtes d’un type donné seront gérées. Les administrateurs configurent souvent plusieurs blocs de serveur et décident ensuite du bloc qui sera chargé de la connexion en fonction du nom du domaine, du port et de l’adresse IP demandés.

      Un bloc de localisation se trouve dans un bloc de serveur. Il permet de définir la façon dont Nginx doit gérer les requêtes pour différentes ressources et URI du serveur parent. L’administrateur peut subdiviser l’espace URI de toutes les manières qu’il le souhaite en utilisant ces blocs. Il s’agit d’un modèle extrêmement flexible.

      Étant donné que Nginx permet à l’administrateur de définir plusieurs blocs de serveur qui fonctionnent comme des instances de serveur virtuel distinctes, il lui faut une procédure qui lui permette de déterminer lesquels de ces blocs utiliser pour satisfaire une requête.

      Pour cela, il passe par un système de vérifications utilisées pour trouver la meilleure correspondance possible. Les directives de bloc de serveur principal que Nginx prend en considération pendant ce processus sont les directives listen et server_name.

      Analyser la directive « listen » pour trouver des correspondances possibles

      Tout d’abord, Nginx examine l’adresse IP et le port de la requête. Il les fait ensuite correspondre avec la directive listen de chaque serveur pour créer une liste des blocs du serveur qui peuvent éventuellement résoudre la requête.

      La directive listen définit généralement l’adresse IP et le port auxquels le bloc de serveur répondra. Par défaut, tout bloc de serveur qui n’inclut pas une directive listen se voit attribuer les paramètres d’écoute de 0.0.0.0:80 (ou 0.0.0.0:8080 si Nginx est exécuté par un non-root user normal). Ces blocs peuvent ainsi répondre aux requêtes sur toute interface sur le port 80. Mais cette valeur par défaut n’a pas beaucoup de poids dans le processus de sélection de serveur.

      La directive listen peut être configurée sur :

      • Un combo adresse IP/port.
      • Une adresse IP unique qui écoutera ensuite le port 80 par défaut.
      • Un port unique qui écoutera chaque interface sur ce port.
      • Le chemin vers une socket Unix.

      La dernière option aura généralement des implications lorsque les requêtes passeront entre les différents serveurs.

      Lorsque Nginx tentera de déterminer le bloc de serveur qui enverra une requête, il tentera d’abord de décider en fonction de la spécificité de la directive listen en utilisant les règles suivantes :

      • Nginx traduit toutes les directives listen « incomplètes » en substituant les valeurs manquantes par leurs valeurs par défaut afin que chaque bloc puisse être évalué par son adresse IP et son port. Voici quelques exemples de ces traductions :
        • Un bloc sans directive listen utilise la valeur 0.0.0.0:80.
        • Un bloc configuré sur une adresse IP 111.111.111.111 sans aucun port devient 111.111.111.111:80
        • Un bloc configuré sur le port 8888 sans adresse IP devient 0.0.0.0:8888
      • Nginx tente ensuite de recueillir une liste des blocs du serveur qui correspondent à la requête de manière plus spécifique en fonction de l’adresse IP et du port. Cela signifie que tout bloc qui utilise fonctionnellement son adresse IP 0.0.0.0 (pour correspondre à toute interface) ne sera pas sélectionné s’il existe des blocs correspondants qui répertorient une adresse IP spécifique. Dans tous les cas, la correspondance avec le port doit être exacte.
      • S’il n’existe qu’une correspondance plus spécifique, la requête sera servie par ce bloc de serveur. En présence de plusieurs blocs de serveur avec le même niveau de spécificité, Nginx commence ensuite à évaluer la directive server_name de chaque bloc de serveur.

      Il est important de comprendre que Nginx évaluera la directive server_name uniquement au moment où il devra faire la distinction entre les blocs de serveur qui correspondent au même niveau de spécificité dans la directive listen. Par exemple, si example.com est hébergé sur le port 80 de 192.168.1.10, le premier bloc servira toujours la requête example.com de cet exemple, malgré la présence de la directive server_name dans le second bloc.

      server {
          listen 192.168.1.10;
      
          . . .
      
      }
      
      server {
          listen 80;
          server_name example.com;
      
          . . .
      
      }
      

      Dans le cas où plusieurs blocs de serveur correspondent à une spécificité égale, l’étape suivante consistera à vérifier la directive server_name.

      Analyser la directive « server_name » pour choisir une correspondance

      Ensuite, pour évaluer les requêtes qui disposent de directives listen également spécifiques, Nginx vérifie l’en-tête « Host » de la requête. Cette valeur contient le domaine ou l’adresse IP que le client a réellement tenté d’atteindre.

      Nginx tente de trouver la meilleure correspondance pour la valeur qu’il trouve en examinant la directive server_name dans chacun des blocs de serveur toujours sélectionnés. Nginx les évalue en utilisant la formule suivante :

      • Nginx tentera d’abord de trouver un bloc de serveur avec un server_name qui correspond à la valeur dans l’en-tête « Host » de la requête exactly. S’il la trouve, la requête sera servie par le bloc associé. S’il trouve plusieurs correspondances exactes, la première est utilisée.
      • S’il ne trouve aucune correspondance exacte, Nginx tentera ensuite de trouver un bloc de serveur avec un server_name correspondant à l’aide d’un métacaractère principal (indiqué par un * au début du nom dans la config). S’il en trouve un, la requête sera servie par ce bloc. S’il trouve plusieurs correspondances, la requête sera servie par la correspondance longest.
      • S’il ne trouve aucune correspondance en utilisant un métacaractère principal, Nginx recherchera ensuite un bloc de serveur avec un server_name correspondant à l’aide d’un métacaractère secondaire (indiqué par un nom de serveur qui se termine par un * dans la config). S’il en trouve un, la requête sera servie par ce bloc. S’il trouve plusieurs correspondances, la requête sera servie par la correspondance longest.
      • S’il ne trouve aucune correspondance en utilisant un métacaractère secondaire, Nginx évalue ensuite les blocs de serveur qui définissent le server_name en utilisant des expressions régulières (indiquées par un ~ avant le nom). Le first server_name avec une expression régulière qui correspond à l’en-tête « Host » sera utilisé pour servir la requête.
      • S’il ne trouve aucune correspondance d’expression régulière, Nginx sélectionne alors le bloc de serveur par défaut pour l’adresse IP et le port en question.

      Chaque combo adresse IP/port est doté d’un bloc de serveur par défaut qui sera utilisé lorsqu’aucun cours d’action ne pourra pas être déterminé avec les méthodes ci-dessus. Pour un combo adresse IP/port, il s’agira soit du premier bloc de la configuration ou du bloc qui contient l’option default_server dans la directive listen (qui remplacera le premier algorithme trouvé). Il ne peut y avoir qu’une seule déclaration default_server pour chaque combinaison adresse IP/port.

      Exemples

      S’il existe un server_name défini qui correspond exactement à la valeur de l’en-tête « Host », ce bloc de serveur sera sélectionné pour traiter la requête.

      Dans cet exemple, si l’en-tête « Host » de la requête est configuré sur « host1.example.com », c’est le second serveur qui sera sélectionné :

      server {
          listen 80;
          server_name *.example.com;
      
          . . .
      
      }
      
      server {
          listen 80;
          server_name host1.example.com;
      
          . . .
      
      }
      

      S’il ne trouve aucune correspondance exacte, Nginx vérifie alors s’il existe un server_name qui commence avec un métacaractère qui convient. Ce sera la correspondance la plus longue et qui commence par un métacaractère qui sera sélectionnée pour répondre à la requête.

      Dans cet exemple, si l’en-tête de la requête indique « Host » pour « www.example.org », c’est le second bloc de serveur qui sera sélectionné :

      server {
          listen 80;
          server_name www.example.*;
      
          . . .
      
      }
      
      server {
          listen 80;
          server_name *.example.org;
      
          . . .
      
      }
      
      server {
          listen 80;
          server_name *.org;
      
          . . .
      
      }
      

      S’il ne trouve aucune correspondance qui commence par un métacaractère, Nginx verra alors s’il existe une correspondance en utilisant un métacaractère à la fin de l’expression. À ce stade, la requête sera servie par la correspondance la plus longue et qui contient un métacaractère.

      Par exemple, si l’en-tête de la requête est configuré sur « www.example.com », ce sera le troisième bloc de serveur qui sera sélectionné :

      server {
          listen 80;
          server_name host1.example.com;
      
          . . .
      
      }
      
      server {
          listen 80;
          server_name example.com;
      
          . . .
      
      }
      
      server {
          listen 80;
          server_name www.example.*;
      
          . . .
      
      }
      

      S’il ne trouve aucune correspondance avec un métacaractère, Nginx tentera alors de faire correspondre les directives server_name qui utilisent des expressions régulières. C’est la first expression régulière correspondante qui sera sélectionnée pour répondre à la requête.

      Par exemple, si l’en-tête « Host » de la requête est configuré sur « www.example.com », c’est alors le second serveur qui sera sélectionné pour satisfaire la requête :

      server {
          listen 80;
          server_name example.com;
      
          . . .
      
      }
      
      server {
          listen 80;
          server_name ~^(www|host1).*.example.com$;
      
          . . .
      
      }
      
      server {
          listen 80;
          server_name ~^(subdomain|set|www|host1).*.example.com$;
      
          . . .
      
      }
      

      Si aucune des étapes ci-dessus ne permet de satisfaire la requête, la requête sera alors transmise au serveur par default de l’adresse IP et le port correspondants.

      Mise en correspondance des blocs de localisation

      Tout comme le processus que Nginx utilise pour sélectionner le bloc de serveur qui traitera une requête, Nginx dispose également d’un algorithme établi pour décider du bloc de localisation du serveur qui servira au traitement des requêtes.

      Syntaxe de bloc de localisation

      Avant de voir de quelle manière Nginx procède pour décider du bloc de localisation qui sera utilisé pour traiter les requêtes, étudions un peu la syntaxe que vous êtes susceptible de rencontrer dans les définitions de bloc de localisation. Les blocs de localisation se trouvent dans les blocs serveur (ou autresblocs de localisation) et servent à décider de quelle manière traité l’URl de la requête (la partie de la demande qui se trouve après le nom du domaine ou l’adresse IP/port).

      Les blocs de localisation ont généralement cette forme :

      location optional_modifier location_match {
      
          . . .
      
      }
      

      Le location_match ci-dessus définit avec quel élément Nginx devrait comparer l’URl de la requête. Dans l’exemple ci-dessus, l’existence ou l’absence du modificateur affecte la façon dont Nginx tente de faire correspondre le bloc de localisation. Les modificateurs donnés ci-dessous entraîneront l’interprétation suivante du bloc de localisation associé :

      • (none) : si aucun modificateur n’est présent, l’emplacement est interprété comme une correspondance de prefix. Cela signifie que la localisation donnée sera comparée avec le début de l’URI de la requête pour voir s’il y a une correspondance.
      • = : si le signe égal est utilisé, ce bloc sera considéré comme une correspondance si l’URI de la requête correspond exactement à la localisation indiquée.
      • ~ : la présence d’un modificateur tilde indique que cet emplacement sera interprété comme une correspondance d’expression régulière sensible à la casse.
      • ~* : si un modificateur tilde et astérisque est utilisé, le bloc de localisation sera interprété comme une correspondance d’expression régulière insensible à la casse.
      • ^~ : si un modificateur de carat et tilde est présent et que ce bloc est sélectionné comme la meilleure correspondance d’expression non régulière, la mise en correspondance des expressions régulières n’aura pas lieu.

      Exemples de la syntaxe d’un bloc de localisation

      Pour vous donner un exemple de correspondance de préfixe, vous pouvez sélectionner le bloc de localisation suivant pour répondre aux URl de requête qui ressemblent à /site, /site/page1/index.html ou /site/index.html:

      location /site {
      
          . . .
      
      }
      

      Pour démontrer une correspondance exacte de l’URI, ce bloc sera toujours utilisé pour répondre à une URI de la requête qui ressemble à /page1. Il ne sera pas utilisé pour répondre à une URI de requête /page1/index.html. N’oubliez pas que, si ce bloc est sélectionné et que la requête est renseignée à l’aide d’une page d’index, le système procédera à une redirection interne vers un autre emplacement qui correspondra au gestionnaire réel de la requête :

      location = /page1 {
      
          . . .
      
      }
      

      Pour vous donner un exemple du type de localisation qui doit être interprétée comme une expression régulière sensible à la casse, vous pouvez utiliser ce bloc pour gérer les requêtes de /tortoise.jpg, mais pas pour /FLOWER.PNG :

      location ~ .(jpe?g|png|gif|ico)$ {
      
          . . .
      
      }
      

      Voici un bloc qui permettrait de faire une mise en correspondance insensible à la casse similaire à ce qui précède : Ici, ce bloc peut gérer /tortoise.jpg et /FLOWER.PNG à la fois :

      location ~* .(jpe?g|png|gif|ico)$ {
      
          . . .
      
      }
      

      Enfin, ce bloc empêchera l’affichage de la correspondance avec l’expression régulière, s’il est configuré de manière à être mis en correspondance avec la meilleure expression non régulière. Il peut gérer les requêtes de /costumes/ninja.html :

      location ^~ /costumes {
      
          . . .
      
      }
      

      Comme vous le voyez, les modificateurs indiquent de quelle manière le bloc de localisation doit être interprété. Cependant, cela ne nous indique pas l’algorithme que Nginx utilise pour décider du bloc de localisation qui enverra la requête. C’est ce que nous allons voir maintenant.

      Nginx choisit la localisation qui sera utilisée pour servir une requête de manière similaire à la façon dont il sélectionne un bloc de serveur. Il passe par un processus qui détermine le meilleur bloc de localisation pour toute requête donnée. Il est vraiment crucial d’avoir une bonne compréhension de ce processus afin de pouvoir configurer Nginx de manière fiable et précise.

      Tout en gardant à l’esprit les types de déclarations de localisation que nous avons décrites ci-dessus, Nginx évalue les contextes de localisation possibles en comparant l’URI de la requête avec chacun des emplacements. Pour cela, il utilise l’algorithme suivant :

      • Nginx commence par vérifier tous les correspondances de localisation sur la base des préfixes (tous les types de localisation qui n’impliquent pas une expression régulière). Il vérifie chaque localisation en fonction de l’URI complet de la requête.
      • Nginx recherche tout d’abord une correspondance exacte. S’il trouve qu’un bloc de localisation qui utilise le modificateur = correspond exactement à l’URI de la requête, ce bloc de localisation est immédiatement sélectionné pour servir la requête.
      • S’il ne trouve aucun bloc de localisation (avec le modificateur =) qui corresponde exactement, Nginx passe alors à l’évaluation des préfixes inexacts. Il trouve la localisation préfixée la plus longue qui correspond à l’URI de la requête donnée, qu’il évalue ensuite de la manière suivante :
        • Si la localisation préfixée la plus longue correspondante contient le modificateur ^~, Nginx arrête immédiatement sa recherche et sélectionnera cette localisation pour servir la requête.
        • Si la localisation préfixée la plus longue correspondante n’utilise pas le modificateur ^~, Nginx enregistre la correspondance pour le moment afin que le focus de la recherche puisse être déplacé.
      • Après avoir déterminé et stocké la localisation préfixée la plus longue correspondante, Nginx passe à l’évaluation des localisations d’expressions régulières (à la fois sensible et insensible à la casse). S’il existe des localisations d’expression régulière à l’intérieur de la localisation préfixée la plus longue correspondante, Nginx les déplacera en haut de la liste des localisations de regex pour procéder à une vérification. Nginx tente ensuite de faire une correspondance avec les localisations d’expression régulières de manière séquentielle. La première localisation d’expressions régulières qui correspond à l’URI de la requête est immédiatement sélectionnée pour servir la requête.
      • S’il ne trouve aucune localisation d’expressions régulières qui corresponde à l’URI de la requête, la localisation préfixée précédemment stockée sera alors sélectionnée pour servir la requête.

      Il est important de comprendre que, par défaut, Nginx préférera servir des correspondances d’expression régulière que des correspondances de préfixe. Cependant, il évalue d’abord les localisations préfixées pour que l’administration puisse écraser cette tendance en spécifiant les localisations avec les modificateurs = et ^~.

      Il est également important de noter que bien que les localisations préfixées sont généralement sélectionnées en fonction de la correspondance la plus spécifique et la plus longue, l’évaluation des expressions régulières s’arrête une fois que la première localisation correspondante est trouvée. Cela signifie que, dans la configuration, le positionnement a un grand impact sur les localisations d’expressions régulières.

      Pour finir, il est important de comprendre que les correspondances d’expressions régulières dans la correspondance de préfixe la plus longue « sauteront la ligne » lorsque Nginx procédera à l’évaluation des localisations de regex. Il procédera à l’évaluation de ces éléments, dans l’ordre, avant même qu’une des autres correspondances d’expression régulière ne soit prise en considération. Dans cet article, Maxim Dounin, un développeur Nginx incroyablement enrichissant, nous explique cette partie de l’algorithme de sélection.

      À quel moment l’évaluation des blocs de localisation passe-t-elle à d’autres localisations ?

      En règle générale, lorsqu’un bloc de localisation est sélectionné pour servir une requête, l’intégralité de la requête est traitée dans ce même contexte à partir de ce moment-là. Seules la localisation sélectionnée et les directives héritées déterminent de quelle manière la requête est traitée, sans que les blocs de localisation apparentés ne viennent interférer.

      Bien qu’il s’agisse d’une règle générale qui vous permettra de concevoir vos blocs de localisation de manière prévisible, il est important que vous sachiez que, parfois, certaines directives dans la localisation sélectionnée déclenchent une nouvelle recherche de localisation. Les exceptions à la règle « seulement un bloc de localisation » peuvent avoir un impact sur la façon dont la requête est effectivement servie et ne seront pas en accord avec les attentes que vous aviez lors de la conception de vos blocs de localisation.

      Voici quelques-unes des directives qui peuvent conduire à ce type de redirection interne :

      • index
      • try_files
      • rewrite
      • error_page

      Examinons-les brièvement.

      La directive index entraîne toujours une redirection interne si elle est utilisée pour gérer la requête. Les correspondances de localisation exactes permettent souvent d’accélérer le processus de sélection en mettant immédiatement fin à l’exécution de l’algorithme. Cependant, si vous effectuez une correspondance de localisation exacte qui est un répertoire, il est possible que la requête soit redirigée vers un autre emplacement pour le traitement en tant que tel.

      Dans cet exemple, la mise en correspondance de la première localisation se fait par un URI de requête /exact, mais pour gérer la requête, la directive index héritée du bloc initialise une redirection interne vers le second bloc :

      index index.html;
      
      location = /exact {
      
          . . .
      
      }
      
      location / {
      
          . . .
      
      }
      

      Dans le cas précédent, si vous souhaitez vraiment que l’exécution reste dans le premier bloc, il vous faudra trouver un moyen différent de satisfaire la requête au répertoire. Par exemple, vous pouvez configurer un index non valide pour ce bloc et activer autoindex :

      location = /exact {
          index nothing_will_match;
          autoindex on;
      }
      
      location  / {
      
          . . .
      
      }
      

      Il s’agit d’un moyen d’empêcher un index de changer de contexte, mais il n’est probablement pas si pratique pour la plupart des configurations. Une correspondance exacte sur les répertoires vous permet la plupart du temps de réécrire la requête par exemple (ce qui peut également générer une nouvelle recherche de localisation).

      Il existe également une autre instance dans laquelle la localisation de traitement peut être réévaluée, avec la directive try_files Cette directive indique à Nginx de vérifier s’il existe un ensemble de fichiers ou de répertoires nommés. Le dernier paramètre peut être un URI vers lequel Nginx procédera à une redirection interne.

      Prenons le cas de la configuration suivante :

      root /var/www/main;
      location / {
          try_files $uri $uri.html $uri/ /fallback/index.html;
      }
      
      location /fallback {
          root /var/www/another;
      }
      

      Dans l’exemple ci-dessus, si une requête est exécutée pour /blahblah, la première localisation obtiendra initialement la requête. Il tentera de trouver un fichier nommé blahblah dans le répertoire /var/www/main. S’il ne peut en trouver, il redirigera sa recherche sur un fichier nommé blahblah.html. Il tentera ensuite de voir s’il existe un répertoire appelé blahblah/ dans le répertoire /var/www/main. Si toutes ces tentatives son un échec, il se redirigera vers /fallback/index.html. Cela déclenchera une autre recherche de localisation que le deuxième bloc de localisation détectera. Cela servira le fichier /var/www/another/fallback/index.html.

      La directive rewrite est également une des autres directives qui permettent de passer un bloc de localisation. Lorsque Nginx utilise le paramètre last avec la directive rewrite, ou n’utilise aucun paramètre du tout, il recherchera une nouvelle localisation correspondante en fonction des résultats de la réécriture.

      Par exemple, si nous modifions le dernier exemple pour y inclure une réécriture, nous pouvons voir que la requête est parfois transmise directement à la seconde localisation sans s’appuyer sur la directive try_files :

      root /var/www/main;
      location / {
          rewrite ^/rewriteme/(.*)$ /$1 last;
          try_files $uri $uri.html $uri/ /fallback/index.html;
      }
      
      location /fallback {
          root /var/www/another;
      }
      

      Dans l’exemple ci-dessus, une requête /rewriteme/hello sera initialement gérée par le premier bloc de localisation. Elle sera réécrite /hello, puis la recherche de la localisation sera déclenchée. Dans ce cas, elle correspondra à nouveau à la première localisation et sera traité par le try_files comme d’habitude, peut même redirigé sur /fallback/index.html si la recherche est infructueuse (en utilisant la redirection interne try_files discutée plus haut).

      Cependant, si une requête /rewriteme/fallback/hello est effectuée, le premier bloc sera à nouveau une correspondance. La réécriture est à nouveau appliquée, ce qui génère cette fois-ci /fallback/hello. La requête sera ensuite servie par le second bloc de localisation.

      La situation est connexe avec la directive return lorsque vous envoyez les codes de statut 301 ou 302. La différence ici est que la requête obtenue et une requête entièrement nouvelle qui prend la forme d’une redirection visible à l’extérieur. Cette même situation peut se produire avec la directive rewrite si vous utilisez les balises redirect ou permanent. Cependant, ces recherches de localisation ne devraient pas être fortuites, car les redirections visibles en externe entraînent toujours une nouvelle requête.

      La directive error_page peut générer une redirection interne similaire à celle créée par try_files. Cette directive permet de définir ce qui devrait se passer si le système rencontre certains codes de statut. Cela ne sera probablement jamais exécuté si try_files est configuré. En effet, cette directive gère l’intégralité du cycle de vie d’une requête.

      Prenons l’exemple suivant :

      root /var/www/main;
      
      location / {
          error_page 404 /another/whoops.html;
      }
      
      location /another {
          root /var/www;
      }
      

      Chaque requête (autres que celles qui commencent par /another) sera traitée par le premier bloc, qui servira les fichiers /var/www/main. Cependant, si un fichier est introuvable (un statut 404), vous verrez se produire une redirection interne vers /another/whoops.html, générant une nouvelle recherche de localisation qui attérira éventuellement sur le second bloc. Ce fichier sera servi à partir de /var/www/another/whoops.html.

      Comme vous pouvez le voir, en comprenant les circonstances dans lesquelles Nginx déclenche une recherche de nouvelle localisation, vous serez plus à même de prévoir le comportement que vous verrez lorsque vous ferez des requêtes.

      Conclusion

      Le fait de comprendre de quelle manière Nginx traite les requêtes clients peut vraiment vous faciliter la tâche en tant qu’administrateur. Vous pourrez savoir quel bloc de serveur Nginx sélectionnera en fonction de chaque requête clients. Vous pourrez également deviner de quelle manière le bloc de localisation sera sélectionné en fonction de l’URI de la requête. Dans l’ensemble, en sachant de quelle manière Nginx sélectionne les différents blocs, vous serez en capacité de reconnaître les contextes que Nginx appliquera pour servir chaque requête.



      Source link