Skip to content

nginx location tester — waarom dat blok wint

Zie welk nginx location-blok wint — en waarom elk ander blok verloor. Gratis tester voor location-matching met =, ^~, ~ en ~*, volledig in je browser.

Geen tracking Draait in je browser Gratis
Je configuratie wordt lokaal in je browser geparset en nooit geüpload. Serverconfigs bevatten upstream-hostnames en auth-blokken, dus open het Network-paneel en kijk hoe het stil blijft — of ga volledig offline.
Probeer een echte misconfiguratie
Geselecteerde location
~* \.(gif|jpg|jpeg)$

Eerste regex in configuratievolgorde die matchte. Lengte is irrelevant.

Waar nginx echt tegenaan matcht
Request-target
/documents/1.jpg
Genormaliseerde $uri
/documents/1.jpg
Query string $args

De matching draait alleen tegen het genormaliseerde pad. De query string wordt er eerst afgesplitst en doet nooit mee.

Waarom dat blok won
Waarom dat blok won
Regel location Fase Uitkomst Reden
2 = / Exact Geen match Een =-location vereist dat de hele URI gelijk is, niet dat die ermee begint.
3 / Prefix Matchte maar korter Het matcht, maar een andere prefix matchte meer tekens.
4 /documents/ Prefix Matchte maar korter Het matcht, maar een andere prefix matchte meer tekens.
5 ^~ /images/ Prefix Geen match De URI begint niet met deze prefix.
6 ~* \.(gif|jpg|jpeg)$ Regex Geselecteerd Eerste regex in configuratievolgorde die matchte. Lengte is irrelevant.

nginx location-modifiers: =, ^~, ~ en ~* vergeleken

nginx location-modifiers: =, ^~, ~ en ~* vergeleken
Modifier Syntaxis Matcht op Volgorde Stopt regex Typisch gebruik
= location = /path Gelijkheid 1 Ja Hot paths zoals / — de snelst mogelijke match.
^~ location ^~ /path Begint met 2 Ja Mappen die nooit aan een regex mogen worden gegeven, zoals uploads.
~ location ~ regex PCRE-regex 3 Nee Routering op extensie waarbij hoofdletters uitmaken.
~* location ~* regex PCRE-regex 3 Nee Routering op extensie waarbij hoofdletters niet uitmaken.
(geen) location /path Begint met 4 Nee Algemene routering op pad.
@ location @name Alleen intern Nee Fallbacks voor error_page en try_files.

De volgordekolom is geen simpele ranglijst. Een prefix-location stopt de regex-evaluatie alleen wanneer die ^~ draagt én zelf de langste match is — en precies daarom lijkt een ^~-blok soms niets te doen.

nginx location-prioriteit: de volgorde van resolutie

nginx location-prioriteit: de volgorde van resolutie
# Fase Beëindigt het zoeken Wat er gebeurt
1 Normaliseren Nee Procent-decodering, oplossen van . en .., herhaalde slashes samengeklapt. De query string wordt hier afgesplitst en doet nooit mee aan de matching.
2 Exact Ja location = /path, vergeleken op gelijkheid. Een treffer beëindigt het zoeken direct.
3 Auto-redirect Ja Een proxy-location waarvan de naam de URI plus een slash is. nginx antwoordt met 301 en komt nooit bij de regexen.
4 Prefix Nee Elke matchende prefix wordt vergeleken en de langste wordt onthouden. De volgorde in de configuratie wordt genegeerd.
5 Genest Nee Er wordt afgedaald in de winnende prefix. Een geneste regex wordt vóór het bovenliggende niveau geprobeerd.
6 Regex Ja Regexen worden geprobeerd in configuratievolgorde en de eerste match wint. Een langere of specifiekere regex die later staat draait nooit.
7 Fallback Ja Geen enkele regex matchte, dus de eerder onthouden prefix wordt gebruikt.
De matchingvolgorde, de ^~-kortsluiting, het afdalen in geneste locations, het gedrag van de automatische redirect en de URI-normalisatie zijn gecontroleerd tegen de broncode van nginx zelf en bevestigd door de configuraties op nginx 1.27.5 te draaien. — Go Tools Engineering Team · Jul 22, 2026

De selectieregels op deze pagina zijn geverifieerd tegen een draaiende nginx 1.27.5 in plaats van overgenomen uit tweedehands artikelen, en de engine wordt gedekt door unittests die uit die runs zijn afgeleid.

nginx location-matching: korte antwoorden

Verwerkt nginx regex-locations vóór prefix-matches?

Nee — prefix-locations worden eerst gecontroleerd, maar een matchende regex wint alsnog. nginx controleert eerst alle prefix-locations en onthoudt de langste match, en evalueert daarna de regex-locations in de volgorde waarin ze in het bestand staan. De eerste matchende regex wint. Matcht er geen enkele regex, dan wordt de onthouden prefix-location gebruikt. De enige uitzondering is ^~: draagt de langste matchende prefix die, dan wordt de regexfase volledig overgeslagen.

Doet de volgorde van location-blokken ertoe in nginx?

Alleen voor regex-locations. Prefix-locations — inclusief = en ^~ — worden geselecteerd op langste match, dus hun volgorde in het bestand is irrelevant. Regex-locations worden van boven naar beneden getest en de eerste match wint, dus een regex-blok verplaatsen verandert welke er draait. Een specifiekere regex die onder een bredere staat, wordt nooit uitgevoerd.

Wat doet de ^~-modifier eigenlijk?

Hij laat nginx stoppen na de prefix-match, in plaats van de prioriteit te verhogen. Draagt de langste matchende prefix-location ^~, dan slaat nginx de regexfase over en gebruikt dat blok. Het maakt de prefix-match niet langer en zet die ook niet boven andere prefixen — het onderdrukt alleen de regex-evaluatie. Daarom lijkt een ^~-blok niets te doen wanneer een langere gewone prefix ook matcht: die langere wordt onthouden, en die onderdrukt niets.

Is location /static hetzelfde als location /static/?

Nee — /static matcht ook /staticfoo. Prefix-matching is een gewone stringvergelijking, geen grens op padsegmenten, dus location /static serveert ook /staticfiles en /static-backup. Los daarvan: wordt /static/ gebruikt met proxy_pass, dan krijgt een request naar /static zonder afsluitende slash een 301-redirect naar /static/ voordat er ook maar één regex wordt bekeken.

Decodeert nginx %2F en klapt het dubbele slashes samen vóór de matching?

Ja — de matching draait tegen de genormaliseerde URI, niet tegen het rauwe request. nginx decodeert %XX, lost . en .. op en comprimeert herhaalde slashes voordat het een location kiest. Een gedecodeerde %2F wordt een echte scheidingsslash en doet mee aan die oplossing, dus /a/b%2F..%2Fzz wordt gematcht als /a/zz. De query string wordt er als eerste afgesplitst en doet nooit mee aan de matching.

Wat is een nginx location-blok?

Een location-blok vertelt nginx wat het moet doen met een request waarvan de URI op een patroon matcht. Een server-blok bevat er meestal meerdere, en het interessante is niet wat elk blok doet maar welk blok nginx kiest — want de selectieregels zijn niet de regels die de meeste mensen aannemen.

Er zijn vijf vormen. location = /path matcht alleen wanneer de hele URI gelijk is. location /path matcht elke URI die met die tekens begint. location ^~ /path is dezelfde prefixvergelijking met één extra effect. location ~ regex en location ~* regex passen een PCRE-patroon toe, hoofdlettergevoelig en hoofdletterongevoelig. location @name doet helemaal niet mee aan URI-matching en bestaat alleen als doel voor try_files en error_page.

De selectie verloopt in fasen. Eerst wordt de URI genormaliseerd: procenttekens gedecodeerd, . en .. opgelost, herhaalde slashes samengeklapt, query string afgesplitst. Daarna beëindigt een =-location die gelijk is aan de URI het zoeken direct. Vervolgens wordt elke matchende prefix vergeleken en wordt de langste onthouden — de volgorde in de configuratie speelt hier geen enkele rol. Draagt die onthouden prefix ^~, dan stopt nginx en gebruikt het dat blok. Anders worden de regex-locations geprobeerd in de volgorde waarin ze in het bestand staan, en wint de eerste match, hoe specifiek een latere ook mag zijn. Matcht er geen enkele, dan wordt de onthouden prefix gebruikt.

Twee van die regels trekken in tegengestelde richting, en daar zit de verwarring: prefixen worden gekozen op lengte ongeacht de volgorde, regexen op volgorde ongeacht de lengte. Een config die van boven naar beneden correct leest, kan een request alsnog ergens heen routeren waar je het niet bedoeld had, en geen enkele herlezing brengt dat aan het licht. Deze pagina speelt de hele reeks opnieuw af op je eigen config en laat zien waar elk blok afviel.

# From the nginx documentation. Which block serves each request?
server {
    location = /                   { }   # A
    location /                     { }   # B
    location /documents/           { }   # C
    location ^~ /images/           { }   # D
    location ~* \.(gif|jpg|jpeg)$  { }   # E
}

#   /                        -> A   exact match, search ends here
#   /index.html              -> B   no regex matched, longest prefix used
#   /documents/document.html -> C   longer prefix than B
#   /images/1.gif            -> D   ^~ won the prefix stage, regex skipped
#   /documents/1.jpg         -> E   regex beats the longer prefix C

# The last two lines are the whole lesson: identical-looking prefixes
# behave differently because only one of them carries ^~.

Functies

Elk verliezend blok, met de fase waarin het afviel

Elk location-blok dat je hebt geschreven krijgt een rij: matchte maar korter, overgeslagen omdat een ^~-prefix won, onbereikbaar omdat een eerdere regex matchte, of gewoon geen match. Weten waarom de anderen verloren is meestal wat de vraag daadwerkelijk beslecht.

De beslissingsketen van vier fasen, opnieuw afgespeeld

Normalisatie, exacte match, het onthouden van de langste prefix, de ^~-kortsluiting, regexen in bestandsvolgorde en de fallback worden als losse stappen tegen je eigen configuratie getoond in plaats van in het abstracte beschreven.

De ^~-kortsluiting zichtbaar gemaakt

Wanneer een ^~-prefix de regexfase onderdrukt, wordt elke overgeslagen regex ook als overgeslagen gelabeld in plaats van stilletjes te verdwijnen — en wanneer de ^~ niet aanslaat omdat een langere gewone prefix won, wordt dat ook getoond.

Geneste locations opgelost, niet platgeslagen

nginx daalt af in de winnende prefix en doorzoekt de kinderen daarvan, dus een geneste regex draait vóór die van het bovenliggende niveau. Geneste blokken houden hun inspringing in de tabel, zodat de structuur leesbaar blijft.

PCRE-specifieke syntaxis vooraf gedetecteerd

Browsers draaien ECMAScript-regexen, geen PCRE. Atomic groups, possessive quantifiers, POSIX-klassen en escapes als \A en \K worden gemarkeerd in plaats van stilzwijgend verkeerd geëvalueerd, zodat een zelfverzekerd fout antwoord nooit als feit wordt gepresenteerd.

Niets wordt geüpload — het draait in je browser

Serverconfigs bevatten upstream-hostnames, interne poorten en authenticatieregels. Het parsen is gewoon stringwerk zonder dependencies en zonder netwerkaanroepen, geverifieerd door een geautomatiseerde contracttest bij elke build.

Andere manieren om deze vraag te beantwoorden

nginx -T

Commandoregel

Dumpt de volledig opgeloste configuratie, wat onmisbaar is om te achterhalen wat er daadwerkelijk geladen is. Het vertelt je niet welke location een gegeven URI selecteert — dat is het gat dat deze pagina vult.

error_log ... debug

Draaiende server

Het gezaghebbendste antwoord dat er is: de regel "using configuration" noemt het blok dat nginx echt heeft gekozen. Het vereist root, een reload en een server die je kunt bereiken — dus het antwoordt ná uitrol, niet ervoor.

Config-syntaxcheckers

Gehoste dienst

Sterk in linting van hele bestanden en in beveiligingsregels. Ze draaien doorgaans server-side, wat betekent dat je een configuratie uploadt met interne hostnames en certificaatpaden erin.

De documentatie lezen

Naslagwerk

De nginx-documentatie beschrijft het algoritme precies en is het waard om één keer te lezen. Het met de hand toepassen op acht blokken en een URI is waar de fouten insluipen, omdat twee van de regels in tegengestelde richting wijzen.

Voorbeelden van nginx location-matching

Een reguliere expressie verslaat een langere prefix

location /documents/  ·  location ~* \.(gif|jpg|jpeg)$  ·  GET /documents/1.jpg
~* \.(gif|jpg|jpeg)$ wins

De prefix /documents/ matcht en is de langste prefix in het bestand, dus nginx onthoudt die — en evalueert daarna toch de reguliere expressies en geeft het request aan de eerste die matcht. Lengte verliest van de regexfase. Was die prefix geschreven als ^~ /documents/, dan was er geen enkele regex uitgevoerd. Dit is het voorbeeld uit de nginx-documentatie, en het is veruit het nuttigste om je eigen te maken.

De uploadmap die PHP uitvoert

location /uploads/  ·  location ~ \.php$ { fastcgi_pass ... }  ·  GET /uploads/evil.php
~ \.php$ wins — the upload lands in the interpreter

De prefix /uploads/ matcht, maar een gewone prefix stopt de regexfase niet, dus een bestand dat iemand heeft geüpload gaat rechtstreeks naar PHP-FPM. location ^~ /uploads/ schrijven sluit de regexfase kort en dicht het gat. Dit is niet hypothetisch: het is de vorm achter een lange reeks upload-naar-RCE-meldingen, en het verschil tussen kwetsbaar en veilig is twee tekens.

^~ die stilletjes niets doet

location ^~ /a/  ·  location /a/b/  ·  location ~ \.php$  ·  GET /a/b/x.php
~ \.php$ wins — the ^~ never applied

^~ onderdrukt de regexfase alleen wanneer het zelf de langste matchende prefix is. Hier is /a/b/ langer, dus dat is degene die nginx onthoudt, en de gewone modifier daarvan laat de regexfase draaien. Het ^~-blok staat nog steeds in het bestand, oogt nog steeds beschermend en heeft geen enkel effect op dit request. Een config van boven naar beneden lezen laat dat niet zien; prefixlengtes vergelijken wel.

/static vangt ook /staticfoo

location /static  ·  location /static/  ·  GET /staticfoo
/static wins

Prefix-matching vergelijkt tekens, geen padsegmenten. /staticfoo begint met /static, dus het matcht, en /static/ matcht helemaal niet omdat de URI op die positie geen slash heeft. Alles wat bereikbaar is onder een pad dat alleen maar met dezelfde letters begint, wordt door dat blok geserveerd — zo komt het dat een /static-regel /static-backup serveert.

De eerste regex wint, niet de beste

location ~ ^/a  ·  location ~ ^/a/b/c$  ·  GET /a/b/c
~ ^/a wins; ~ ^/a/b/c$ is unreachable

Reguliere expressies worden geëvalueerd in de volgorde waarin ze in het bestand staan en de eerste match beëindigt het zoeken. Het tweede blok is specifieker en matcht deze URI exact, en het zal nooit draaien — voor geen enkel request. Prefix-locations worden gekozen op lengte ongeacht de volgorde; regex-locations op volgorde ongeacht de specificiteit. Die twee regels door elkaar halen is de gebruikelijke reden dat een regel "niet meer werkt" nadat iemand het bestand heeft opgeruimd.

Gecodeerde traversal wordt vóór de matching opgelost

location /a/  ·  location /b/  ·  GET /a/b%2F..%2Fzz
$uri becomes /a/zz, so /a/ wins

nginx decodeert procenttekens, lost . en .. op en klapt herhaalde slashes samen voordat er ook maar één location wordt geraadpleegd. %2F decodeert naar een echte scheidingsslash en doet daarna mee aan die oplossing, dus dit target blijft niet binnen /a/b/ — het komt uit op /a/zz. Matchen tegen het target dat je hebt getypt in plaats van tegen de genormaliseerde $uri geeft hier het verkeerde antwoord.

Zo gebruik je de nginx location tester

  1. 1

    Plak het server-blok

    Gooi er een compleet server-blok in, of alleen de location-blokken waarover je nadenkt. Geneste locations worden begrepen en de oorspronkelijke regelnummers blijven behouden, zodat de tabel op je bestand aansluit.

  2. 2

    Voer de request-URI in

    Typ het pad zoals het binnenkomt, inclusief eventuele procentcodering en query string. De drie rijen boven de tabel laten zien hoe het vóór de matching wordt genormaliseerd.

  3. 3

    Lees de winnaar, daarna de verliezers

    De uitspraakkaart noemt het geselecteerde blok en de reden in één regel. De beslissingstabel eronder legt elk ander blok uit: in welke fase het afviel en waarom.

  4. 4

    Bekijk de diagnostiek

    Niet-verankerde regexen, prefixen zonder afsluitende slash, een ^~ met een regexpatroon erachter, onbereikbare duplicaten en uploadmappen die bereikbaar zijn via een PHP-regex worden allemaal gemeld.

  5. 5

    Deel de exacte staat

    Kopieer link codeert de config en de URI in het URL-fragment, zodat een collega precies opent wat jij voor je hebt. Fragmenten worden nooit naar een server verstuurd.

Veelgemaakte fouten met nginx locations

Verwachten dat ^~ boven een langere prefix uitkomt

^~ wordt alleen bekeken op de prefix die al op lengte gewonnen heeft. Een langere gewone prefix wint eerst, en de regexfase draait daarna alsof de ^~ er niet was.

✗ Fout
location ^~ /a/ { }
location /a/b/ { }
location ~ \.php$ { }
# /a/b/x.php -> ~ \.php$
✓ Correct
location ^~ /a/ { }
location ^~ /a/b/ { }
location ~ \.php$ { }
# /a/b/x.php -> ^~ /a/b/

Een prefix zonder afsluitende slash die buren opvangt

Prefix-matching vergelijkt tekens in plaats van padsegmenten, dus het blok bedient ook elk buurpad dat met dezelfde letters begint.

✗ Fout
location /static { root /var/www; }
# also serves /staticfoo and /static-backup
✓ Correct
location /static/ { root /var/www; }
location = /static { return 301 /static/; }

De specifieke regex onder de brede zetten

Regexen worden geprobeerd in bestandsvolgorde en de eerste match beëindigt het zoeken, dus het preciezere blok draait nooit, voor geen enkel request.

✗ Fout
location ~ ^/api { }
location ~ ^/api/v2/users$ { }
# the second is unreachable
✓ Correct
location ~ ^/api/v2/users$ { }
location ~ ^/api { }

Een regex achter ^~ schrijven

^~ neemt een letterlijke prefix. nginx laadt het bestand zonder klagen en het blok matcht simpelweg nooit ergens op, waardoor het lastig te zien is in review.

✗ Fout
location ^~ "\.php$" { deny all; }
✓ Correct
location ~ \.php$ { deny all; }

Aannemen dat de query string meedoet aan de matching

De query string wordt tijdens de normalisatie afgesplitst, dus een location kan er nooit op matchen. Lees in plaats daarvan $arg_name binnen het blok uit.

✗ Fout
location /search?q= { }
# never matches anything
✓ Correct
location /search {
    if ($arg_q = "") { return 400; }
}

Wat je met de nginx location tester kunt doen

Een config controleren voordat hij productie haalt
Redeneer over de routering van een server-blok dat je hebt aangepast maar nog niet hebt uitgerold. De storing die dit opvangt is die welke alleen bij een bepaalde vorm van URI opduikt, precies het soort dat een smoketest na de reload doorgaans mist.
Uitzoeken waarom een regel niet meer werkt
Een regex die eerst draaide en nu niet meer is bijna altijd slachtoffer van volgorde: iets matchte eerder, of er is een ^~ boven verschenen. De tabel markeert het blok als onbereikbaar en noemt het blok dat het request heeft gepakt.
Een upload- of mediamap auditen
Laad de preset die het upload-uitvoerpatroon reproduceert en plak daarna je eigen paden. Pakt een PHP-regex requests binnen een map waar geschreven mag worden, dan zegt de diagnostiek dat en noemt beide blokken.
Een reviewopmerking met bewijs afsluiten
Kopieer link legt de exacte config en URI vast in het URL-fragment. Dat in een pull request plakken vervangt een discussie over voorrang door een beslissingstabel die iedereen opnieuw kan draaien.
Het selectiealgoritme uitleggen
De twee referentietabellen zijn statisch, crawlbaar materiaal waar je naar kunt verwijzen, en de preset-chips demonstreren elke valkuil zonder dat je een server hoeft te slopen. Vooral het ^~-voorbeeld beëindigt de discussie meestal snel.

Hoe nginx een location selecteert

Normalisatie gebeurt voordat er een location wordt geraadpleegd
De URI wordt procent-gedecodeerd, de segmenten . en .. worden opgelost en herhaalde slashes worden samengeklapt, en pas dan wordt er een location gekozen. Een gedecodeerde %2F wordt een echte scheidingsslash en doet mee aan die oplossing, dus /a/b%2F..%2Fzz wordt gematcht als /a/zz. Drie gedecodeerde tekens zijn een uitzondering en blijven letterlijk: %25, %23 en %3F — daarom heeft /a%3Fx=1 een vraagteken in het pad en een lege query string. Een + is hier geen spatie; alleen %20 is dat. Traversal boven de root en een ongeldige escape worden allebei met een 400 geweigerd voordat de matching begint.
Prefixlengte beslist, de volgorde in de configuratie niet
Elke prefix-location die matcht wordt vergeleken en de langste wint, of die nu eerst of laatst in het bestand staat. De vergelijking gaat per teken, niet per padsegment, dus /static matcht /staticfoo. De winnaar wordt onthouden in plaats van meteen gebruikt, omdat de regexfase hem nog kan overrulen.
^~ onderdrukt regexen; het verhoogt de prioriteit niet
De modifier wordt alleen bekeken op de prefix die al op lengte gewonnen heeft. Matcht er ook een langere gewone prefix, dan wordt díe onthouden en draait de regexfase gewoon door — het ^~-blok heeft dan geen enkel effect op het request. ^~ op een geneste location plaatsen beschermt niet tegen een regex die op het buitenste niveau is gedeclareerd, en het onderdrukt nooit de regexen die binnen het blok zelf genest zitten.
Regexen draaien in bestandsvolgorde en de eerste match beëindigt het zoeken
nginx houdt regex-locations in de volgorde waarin ze zijn geschreven en sorteert ze niet. Specificiteit, lengte en verankering hebben geen invloed op welke als eerste wordt geprobeerd, dus een precies patroon dat onder een breed patroon staat is dode configuratie. In een regex-location die gematcht heeft wordt alsnog afgedaald, dus de daarin geneste locations worden daarna doorzocht.
PCRE en ECMAScript zijn niet dezelfde taal
nginx compileert location-regexen met PCRE, zonder UTF- of multiline-modus, dus patronen werken op bytes en ^ verankert alleen aan het begin van de URI. Eén verschil heeft veiligheidsgewicht: de $ van PCRE matcht ook net vóór een afsluitende newline, dus een URI die op %0A eindigt voldoet alsnog aan \.php$, ook al zou een JavaScript-engine dat weigeren. Dat gedrag wordt hier geëmuleerd en gemeld, want het is een bekende manier om langs regels op bestandsextensie te glippen.

Best practices voor nginx locations

Bescherm schrijfbare mappen met ^~, niet met een gewone prefix
Elke map die uploads accepteert heeft location ^~ /uploads/ nodig, zodat de regexfase een opgeslagen bestand niet aan een interpreter kan geven. Een gewone prefix ziet er gelijkwaardig uit en is dat niet.
Geef mapprefixen een afsluitende slash
Schrijf location /static/ in plaats van location /static, tenzij je bewust wilt dat /staticfoo en /static-backup door hetzelfde blok worden bediend. Voeg een aparte location = /static toe wanneer het kale pad ook afgehandeld moet worden.
Zet regexen op volgorde van specifiek naar breed
De eerste match wint, dus een breed patroon boven een precies patroon maakt dat precieze onbereikbaar. Weinig regexen aanhouden en ze bewust ordenen is makkelijker te onderhouden dan achteraf over overlap redeneren.
Veranker regexen die een padprefix moeten matchen
location ~ /admin zoekt overal in de URI en matcht /public/admin/x. Schrijf ~ ^/admin als je het begin bedoelt. Alleen aan het eind verankeren is normaal en correct voor routering op extensie.
Controleer de routering opnieuw na elke herordening
Blokken verplaatsen is veilig voor prefixen en verandert het gedrag van regexen. Omdat een diff die alleen regels verplaatst er onschuldig uitziet in review, is de betrokken URI's opnieuw draaien de goedkoopste manier om het te vangen.

Veelgestelde vragen over de nginx location tester

Hoe debug ik welke location nginx heeft gekozen?
Plak de config en de request-URI in deze tester om het winnende blok te zien en de reden waarom elk ander blok afviel. Op een draaiende server voeg je error_log /var/log/nginx/debug.log debug; toe en zoek je de regel "using configuration", die de geselecteerde location noemt. De twee aanpakken beantwoorden verschillende vragen: het log vertelt wat een live server heeft gedaan, en deze pagina vertelt wat een config die je nog niet hebt uitgerold zou doen.
Waarom werkt mijn nginx location-regex niet?
Meestal om een van drie redenen, en de beslissingstabel benoemt welke. Een eerdere regex matchte al, dus die van jou draaide nooit — regexen worden geprobeerd in bestandsvolgorde en de eerste match wint. Of de langste matchende prefix draagt ^~, waardoor de regexfase volledig wordt overgeslagen. Of de regex klopt maar de URI is niet wat je denkt: de matching draait tegen het genormaliseerde pad, na procent-decodering en het oplossen van .., met de query string eraf.
Waarom slaat mijn exacte match niet aan?
Een =-location vereist dat de hele URI gelijk is, niet dat die met het patroon begint. location = /a/ matcht /a niet, en location = /a matcht /a/b niet. Afsluitende slashes zijn hier gewone tekens, dus de twee vormen zijn verschillende strings. Matcht een exacte location wel, dan stopt het zoeken direct en wordt er verder niets meer vergeleken.
Matcht nginx de query string in een location-blok?
Nee. De query string wordt tijdens de normalisatie afgesplitst en de location-selectie draait alleen tegen het pad. Daarom matcht location = /a op een request naar /a?x=/b. Wil je vertakken op een parameter, dan moet je $arg_name of $args binnen het blok uitlezen. Eén subtiliteit is het waard om te kennen: %3F decodeert naar een letterlijk vraagteken dat in het pad blijft staan, dus /a%3Fx=1 heeft een lege query string en een pad met ? erin.
Kan ik JavaScript-regexsyntaxis gebruiken in een nginx location?
Nee — nginx gebruikt PCRE, en de verschillen doen ertoe. Deze pagina draait in je browser, waar alleen ECMAScript-reguliere expressies bestaan, dus PCRE-specifieke constructies worden gedetecteerd en gemarkeerd in plaats van stilzwijgend verkeerd geëvalueerd: atomic groups, possessive quantifiers, inline modifiers zoals (?i), POSIX-klassen zoals [[:alpha:]], en escapes als \A en \K die JavaScript geruisloos als gewone letters leest. Wordt een location gemarkeerd, dan worden de overige kandidaten nog steeds in de volgorde van nginx geëvalueerd, maar het oordeel over dat blok moet je op een echte server controleren. Schrijf je het patroon zelf, dan behandelt de regex-tester de ECMAScript-syntaxis uitgebreid.
Zijn prefix-matches van nginx locations hoofdlettergevoelig?
Op Linux wel — location /Static/ matcht /static/x niet. Op niet-hoofdlettergevoelige bestandssystemen zoals macOS en Cygwin vergelijkt nginx prefixen hoofdletterongevoelig en dwingt het bovendien elke regex-location zich te gedragen als ~*. Deze pagina modelleert het Linux-gedrag, en dat is wat productieservers vrijwel altijd draaien. Ontwikkel je op een Mac en rol je uit naar Linux, dan kan dat verschil een kapotte regel verbergen tot hij live gaat.
Verandert try_files welk location-blok is geselecteerd?
Nee. De location-selectie is eerst klaar; try_files draait daarna, binnen het blok dat al gewonnen heeft. Bereikt een request nooit het blok met jouw try_files, dan is de directive irrelevant — de gebruikelijke oorzaak is een ~ \.php$-regex die het request pakt voordat het prefix-blok met de fallback aan bod komt. Een interne redirect die later wordt uitgestuurd start de matching wel opnieuw, dus een herschreven URI wordt weer vanaf de bovenkant tegen de location-lijst opgelost.
Waarom geeft nginx een 301 als ik een map zonder slash opvraag?
Daar zitten twee verschillende mechanismen achter. Draagt een location waarvan de naam op / eindigt een proxy_pass of een andere *_pass-directive, dan wordt een request naar hetzelfde pad zonder slash tijdens de location-selectie met een 301 beantwoord — voordat er ook maar één regex is geëvalueerd. Los daarvan geeft de module voor statische bestanden een 301 wanneer het pad naar een echte map op schijf verwijst. De eerste is hier zichtbaar; de tweede hangt van je bestandssysteem af. location = /path toevoegen onderdrukt de eerste.
Veranderen geneste location-blokken de uitkomst?
Ja, en op een manier die je makkelijk mist. nginx daalt af in de winnende prefix-location en doorzoekt de kinderen daarvan, dus een geneste regex wordt vóór de regexen van het bovenliggende niveau geprobeerd. Een ^~ op het buitenste blok schermt het niet af tegen zijn eigen geneste regexen, en nesting kan een globaal langere prefix onbereikbaar maken wanneer een broer op het buitenste niveau eerst wint. Geneste blokken worden hier gemodelleerd met dezelfde inspringing als waarmee je ze hebt geschreven.
Wordt mijn nginx-configuratie ergens geüpload?
Nee. Het parsen en matchen gebeurt lokaal in je browser met gewone stringbewerkingen — er is geen serveraanroep en er wordt niets bewaard. Dat weegt hier zwaarder dan bij de meeste tools, omdat een echt server-blok upstream-hostnames, interne poorten, certificaatpaden en authenticatieregels bevat. Je hoeft ons niet op ons woord te geloven: open de developer tools van je browser en kijk hoe het Network-paneel stil blijft terwijl je typt, of verbreek je verbinding helemaal en test door. Dat er geen enkel extern verzoek is, wordt bovendien bij elke build afgedwongen door een geautomatiseerde contracttest, dus het kan niet stilletjes terugvallen.

Gerelateerde tools

Alle tools bekijken →