Regex in Nginx-Location-Blöcken sind dann sinnvoll, wenn Pfade nicht nur hierarchisch, sondern nach Mustern geroutet werden müssen: Dateiendungen, API-Versionen, Legacy-URLs oder gezielte Weiterleitungen. Ich zeige hier, wie Nginx solche Regeln priorisiert, wie man saubere Muster schreibt und welche Stolperfallen im Alltag am häufigsten Zeit kosten. Der Fokus liegt auf produktiven Webserver-Setups, nicht auf Lehrbuchsyntax.
Die wichtigsten Punkte auf einen Blick
- Nginx prüft zuerst Prefix-Locations, danach Regex in der Reihenfolge ihrer Definition.
- Das Matching betrifft nur die normalisierte URI, nicht den Query-String.
-
~ist case-sensitive,~*ist case-insensitive. -
^~verhindert, dass spätere Regex den gewählten Prefix verdrängen. - In Regex-Locations setze ich
proxy_passohne URI ein. - Saubere Anker, sparsame Captures und Tests sind wichtiger als komplizierte Muster.

So entscheidet Nginx über ein Regex-Location
Ich sehe oft die Annahme, Nginx gehe die Blöcke einfach von oben nach unten durch. Tatsächlich prüft er zuerst Prefix-Locations, merkt sich den längsten passenden Prefix und läuft danach die Regex in der Reihenfolge ihrer Definition ab. Der erste Regex-Treffer gewinnt; nur wenn keiner passt, bleibt der gemerkte Prefix aktiv. Zusätzlich arbeitet Nginx auf der normalisierten URI, also nach dem Decoding von %XX, der Auflösung von . und .. und dem Zusammenziehen mehrerer Schrägstriche.
| Modifikator | Was er bedeutet | Wann ich ihn nutze |
|---|---|---|
= |
Exakter Treffer, Suche endet sofort | Für eine ganz bestimmte URI wie / oder /healthz
|
| Prefix | Längster passender Prefix | Für Ordnerpfade wie /static/ oder /app/
|
^~ |
Prefix gewinnt gegen Regex | Wenn ein Bereich garantiert nicht von Regex verdrängt werden soll |
~ |
Regex, case-sensitive | Wenn Schreibweise sauber und bewusst ist |
~* |
Regex, case-insensitive | Für Dateiendungen oder inkonsistente Groß-/Kleinschreibung |
Wenn diese Reihenfolge sitzt, werden Regex-Regeln vorhersehbar statt überraschend. Als Nächstes lohnt sich deshalb der Blick auf die Muster selbst.
Welche Regex-Schreibweise in der Praxis trägt
Für location-Regeln verwende ich keine wilden Ausdrücke, sondern kleine, nachvollziehbare Muster. Ein ^ am Anfang und ein $ am Ende begrenzen die Regel auf genau den gewünschten Pfad; \. schützt den Punkt als Literal; und (?:...) ist mein Standard, wenn ich nur gruppieren, aber nicht unnötig capturen will. Das spart Fehler und hält die spätere Weiterverarbeitung sauber.
-
[^/]statt.*für Pfadsegmente, damit ein Muster nicht versehentlich über Verzeichnisse hinausläuft. -
~*nur dort, wo es wirklich nötig ist, etwa bei gemischten Dateiendungen oder alten CMS-URLs. -
Named Captures wie
(?, wenn der Wert später in einer Umleitung oder im Logging genutzt wird.[^/]+)
location ~* ^/assets/[^/]+\.(?:css|js|map)$ {
expires 7d;
access_log off;
}Die Regel greift nur für echte Asset-Dateien unter /assets/ und bleibt auch dann stabil, wenn irgendwo ein zusätzlicher Slash auftaucht. Ich halte solche Muster lieber knapp und eindeutig, statt sie mit unnötigen Alternativen aufzuweichen.
location ~ ^/api/v(?[0-9]+)/ {
proxy_pass http://api_backend;
} Der Captured-Wert $version ist dann in anderen Direktiven verfügbar. Ich nutze das sparsam, aber genau dann, wenn Routing und Beobachtbarkeit zusammengehören. Mit diesen Bausteinen lassen sich bereits sehr präzise Wege bauen. In echten Setups zeigen sie ihren Wert vor allem bei statischen Dateien, APIs und Migrationen.
Drei typische Einsatzmuster aus produktiven Setups
Ich baue Regex-`location`-Regeln meist für drei Szenarien: statische Assets, versionierte APIs und Legacy-Routen. Jedes davon spart mir an anderer Stelle Wartung, wenn die Regel eng genug bleibt.
Dateiendungen sauber cachen
Wenn Assets über Dateiendungen unterschieden werden, ist eine Regex-Location oft der sauberste Weg. Sie trennt cachebare Dateien von allem anderen, ohne dass ich jeden Ordner einzeln pflegen muss.
location ~* \.(?:gif|jpe?g|png|webp|svg|ico)$ {
expires 30d;
access_log off;
}Der Nutzen liegt nicht nur im Caching. Die Regel verhindert auch, dass ein CMS oder ein Build-Prozess neue Bildtypen plötzlich außerhalb des gewünschten Pfads ausliefert. Ich halte solche Regeln bewusst knapp und ergänze lieber gezielt weitere Endungen, als ein überlanges Monster zu bauen.
API-Versionen trennen
Bei versionierten APIs will ich die Struktur im Pfad sichtbar halten, ohne für jede Variante einen eigenen Prefix-Block zu schreiben. Genau dafür eignet sich eine Regex-Lösung sehr gut.
location ~ ^/api/v(?[0-9]+)/ {
proxy_pass http://api_backend;
} Damit kann ich unterschiedliche Versionen derselben API auf denselben Upstream legen, ohne die URL-Struktur im Backend zu verlieren. Wenn Versionen später anders behandelt werden müssen, habe ich den Marker bereits sauber im Pfad.
Lesen Sie auch: Darknet verstehen - Technik, Risiken & echte Anonymität
Legacy-Pfade kontrolliert umleiten
Migrationen sind der Fall, in dem Regex-Locations besonders nützlich werden. Alte Links bleiben erreichbar, während ich das Zielsystem schrittweise auf eine neue Struktur bringe.
location ~ ^/old-blog/(?[^/]+)/?$ {
return 301 /blog/$slug;
} Das ist hilfreich, weil ich optionales Trailing Slash sauber abfange und alte Links nicht ins Leere laufen lasse. Eine hart codierte Liste aus Einzel-Redirects wird hier schnell unwartbar; ein klarer Regex ist in solchen Fällen meist die bessere Redaktion. Bei Weiterleitungen zum Upstream ist aber ein Detail wichtig, das in vielen Configs übersehen wird.
Worauf ich bei proxy_pass und Redirects achte
Regex-Locations und proxy_pass vertragen sich gut, aber nicht mit halbgaren URI-Umbauten. Wenn ein location per Regex definiert ist, setze ich proxy_pass ohne URI-Pfad ein, weil Nginx den Teil, der ersetzt werden müsste, nicht eindeutig bestimmen kann. Alles andere führt schnell zu Konfigurationen, die zwar syntaktisch akzeptiert werden, aber semantisch nicht das tun, was man erwartet.
-
Bei Regex-Locations kein zusätzlicher URI-Pfad in
proxy_pass- der Upstream soll die vollständige URI bekommen oder die Umschreibung findet vorher statt. -
Captures gezielt nutzen - etwa für
return 301, Header oder Logging, nicht als Vorwand für komplizierte Pfadmathematik. -
Wenn die Entscheidung von Parametern abhängt, ist
locationdas falsche Werkzeug; dafür nehme ich ehermapoder die Anwendung selbst.
location ~ ^/service/(?[^/]+)/ {
proxy_pass http://service_backend;
} So bleibt der Upstream-Pfad eindeutig und ich muss später nicht rätseln, ob Nginx gerade Teile der URI ersetzt oder nicht. Genau das macht Regex-Setups im Betrieb robuster. Sobald die Weitergabe sauber ist, bleiben die klassischen Fehler, die sich meist erst im Live-Betrieb bemerkbar machen.
Die häufigsten Stolperfallen mit Regex-Locations
Die meisten Probleme entstehen nicht durch die Regex-Engine selbst, sondern durch zu viel Freiheit in der Konfiguration. Ich achte besonders auf diese Punkte:
-
Zu breite Muster -
.*fängt schnell mehr ab als geplant, vor allem ohne Anker. - Falsche Reihenfolge - bei Regex zählt die Reihenfolge in der Datei; der erste Treffer gewinnt.
-
Query-String-Missverständnisse -
locationprüft nur den URI-Teil, nicht?a=boder andere Parameter. - Regex statt Prefix - für einfache Verzeichnisse ist ein Prefix klarer und leichter zu warten.
-
Vergessene
^~-Absicherung - ein statischer Bereich kann sonst von späteren Regex wieder eingefangen werden. - Zu viele Captures - wenn ein Wert nirgends weiterverwendet wird, macht er die Regel nur unruhiger.
In der Praxis teste ich jede Änderung mit nginx -t und dann mit zwei oder drei realen URLs, die den Grenzfall wirklich abdecken. Das ist deutlich verlässlicher als auf Sicht zu glauben, der Regex sei schon „ungefähr richtig“. Wenn man diese Fehlerquellen im Griff hat, wird die letzte Entscheidung überraschend einfach: Welche Art von location passt überhaupt zum Problem?
Wann ich =, Prefix oder Regex wähle
Ich entscheide das nicht nach Geschmack, sondern nach Struktur der URL. Ein exakter Match ist ideal für einzelne feste Pfade, ein Prefix für echte Pfadbäume, und Regex nur dann, wenn ein Muster mehrere Varianten sauber zusammenfasst. Alles andere ist meist unnötige Komplexität.
| Typ | Wann ich ihn wähle | Vorteil | Grenze |
|---|---|---|---|
= |
Genau eine URI wie /healthz
|
Sehr klar, endet sofort | Kein Muster möglich |
| Prefix | Ordnerartige Pfade wie /static/
|
Lesbar, wartbar | Keine inhaltliche Musterlogik |
^~ |
Ein Prefix soll Vorrang behalten | Blockiert Regex-Fallback | Kann nützliche Regex bewusst ausschließen |
~ / ~*
|
Endungen, Versionen, Legacy-Pfade | Flexibel und präzise | Stark von Ordnung und Sorgfalt abhängig |
Meine Daumenregel: Sobald ich die Regel ohne Regex in einem Satz beschreiben kann, prüfe ich zuerst Prefix oder exact. Regex kommt erst dann dran, wenn das Routing sonst ausufert oder sich unnötig vervielfacht. Damit bleibt die Konfiguration kurz, lesbar und im Team nachvollziehbar.
Was ich vor dem Rollout noch einmal prüfe
Vor dem Rollout gehe ich die Konfiguration noch einmal mit drei Fragen durch: Ist die Priorität eindeutig, sind die Anker wirklich eng genug, und bleibt der Pfad auch in sechs Monaten verständlich, wenn jemand anderes die Datei anfasst? In produktiven Webservern gewinnt fast immer die Regel, die sich am einfachsten erklären lässt.
- Nur so viel Regex wie nötig
- Exakte Pfade und Prefixe bevorzugen, wenn sie reichen
- Regex-Locations auf echte Muster beschränken
- Änderungen mit
nginx -tund realen Requests prüfen
Wenn du diese Linie konsequent fährst, werden Nginx-Location-Regeln nicht zum Rätsel, sondern zu einem präzisen Werkzeug für sauberes URL-Matching.