Nginx Reverse Proxy und Load Balancing: Unterschied zwischen den Versionen
Links auf die drei Nginx-Animationen angepasst |
Erweitertes Routing ergaenzt, Links auf neue Seiten |
||
| Zeile 118: | Zeile 118: | ||
<code>burst=10 nodelay</code> lässt kurze Spitzen bis 10 Anfragen sofort durch, statt sie zu verzögern. Wird die Rate dauerhaft überschritten, antwortet Nginx selbst mit <b>429 Too Many Requests</b> – das Backend bekommt die Anfrage gar nicht erst zu sehen. | <code>burst=10 nodelay</code> lässt kurze Spitzen bis 10 Anfragen sofort durch, statt sie zu verzögern. Wird die Rate dauerhaft überschritten, antwortet Nginx selbst mit <b>429 Too Many Requests</b> – das Backend bekommt die Anfrage gar nicht erst zu sehen. | ||
== Erweitertes Routing == | |||
=== SPA-Fallback === | |||
<pre> | |||
location / { | |||
try_files $uri $uri/ /index.html; | |||
} | |||
</pre> | |||
Für Single-Page-Applications: Existiert die angeforderte Datei nicht, liefert Nginx stattdessen <code>index.html</code> aus – das clientseitige Routing im Browser übernimmt den Rest. | |||
=== Named Location === | |||
<pre> | |||
location / { | |||
try_files $uri @backend; | |||
} | |||
location @backend { | |||
proxy_pass http://127.0.0.1:3000; | |||
} | |||
</pre> | |||
Eine Named Location (<code>@name</code>) ist nur intern erreichbar, nie direkt über eine URL – praktisch als Fallback-Ziel für <code>try_files</code>. | |||
=== map-Direktive === | |||
<pre> | |||
map $http_upgrade $connection_upgrade { | |||
default upgrade; | |||
"" close; | |||
} | |||
</pre> | |||
<code>map</code> erzeugt im <code>http</code>-Kontext eine neue Variable in Abhängigkeit vom Wert einer anderen – hier für den WebSocket-Header <code>Connection</code> genutzt (siehe Abschnitt „Reverse Proxy: proxy_pass und Header“). | |||
== Fehlerbilder == | == Fehlerbilder == | ||
| Zeile 141: | Zeile 177: | ||
* [https://nginx.org/en/docs/ offizielle Nginx-Dokumentation] | * [https://nginx.org/en/docs/ offizielle Nginx-Dokumentation] | ||
* [[Nginx Grundlagen]] | * [[Nginx Grundlagen]] | ||
* [[Nginx Lets Encrypt und Certbot]] | |||
* [[Nginx Absichern und Betreiben]] | |||
* Animationen: [https://xinux.org/nginx-grundkonfiguration.html Grundkonfiguration] · [https://xinux.org/nginx-reverse-proxy.html Reverse Proxy] · [https://xinux.org/nginx-load-balancing.html Load Balancing] | * Animationen: [https://xinux.org/nginx-grundkonfiguration.html Grundkonfiguration] · [https://xinux.org/nginx-reverse-proxy.html Reverse Proxy] · [https://xinux.org/nginx-load-balancing.html Load Balancing] | ||
Aktuelle Version vom 31. Oktober 2026, 14:14 Uhr
Vertiefung zu Nginx Grundlagen: Location-Matching, Reverse Proxy, Load Balancing, Caching und Rate Limiting – mit den typischen Fehlerbildern. Dazu die Animationen Nginx: Grundkonfiguration (Einstieg), Nginx: Reverse Proxy (erweitert) und Nginx: Load Balancing (fortgeschritten).
Location-Matching: welche Regel gewinnt
Nginx wählt die passende location nicht nach der Reihenfolge im Config, sondern nach festen Regeln:
- Exact Match (
location = /pfad) – trifft nur exakt, gewinnt sofort - Prefix Match – der längste passende Prefix gewinnt
- Ist der Prefix mit
^~markiert, stoppt hier die Prüfung – keine Regex mehr - sonst: alle Regex-Locations (
~case-sensitive,~*case-insensitive) der Reihe nach, die erste passende gewinnt – und zwar über dem Prefix - ohne Regex-Treffer: Fallback auf den längsten Prefix aus Schritt 2
Der Klassiker: Regex schlägt Prefix
location /download/ {
limit_rate 500k; # Downloads drosseln
}
location ~* \.(zip|iso)$ {
limit_rate 5m; # war für andere Zwecke gedacht
}
Eine Anfrage nach /download/archiv.zip passt auf beide Blöcke. Da der Prefix kein ^~ hat, gewinnt die Regex-Regel – die Datei wird entgegen der Absicht nicht gedrosselt. Lösung: den Prefix mit ^~ markieren, dann gewinnt er garantiert gegen jede Regex:
location ^~ /download/ {
limit_rate 500k; # gilt jetzt für alles unter /download/
}
Reverse Proxy: proxy_pass und Header
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
Ohne diese Header sieht die Backend-App nur Nginx selbst (127.0.0.1) als Quelle – Client-IP, ursprünglicher Host und Protokoll gehen verloren. Wichtig: Eine App darf X-Forwarded-For nur von bekannten, kontrollierten Proxys vertrauen, sonst lässt sich der Header von jedem fälschen, der die App direkt erreicht.
Für WebSockets zusätzlich:
proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade";
Load Balancing
upstream app_backend {
server 10.0.0.11:3000;
server 10.0.0.12:3000;
}
server {
location / {
proxy_pass http://app_backend;
}
}
Verteilmethoden
| Methode | Verhalten |
|---|---|
| weighted round robin (Default) | reihum, optional mit Gewicht je Server (weight=3)
|
least_conn |
an den Server mit den wenigsten aktiven Verbindungen |
ip_hash |
gleiche Client-IP landet immer beim gleichen Server (Session-Affinität ohne gemeinsamen Session-Speicher, aber ungleich verteilt bei NAT/Firmennetz) |
Ausfall eines Backends
upstream app_backend {
server 10.0.0.11:3000 max_fails=3 fail_timeout=30s;
server 10.0.0.12:3000;
}
Das freie Nginx erkennt einen Ausfall nur passiv: Erst wenn echte Anfragen fehlschlagen, zählt das. Nach max_fails Fehlschlägen wird der Server für fail_timeout ausgeschlossen. Aktive, regelmäßige Health-Checks gibt es nur in kommerziellen oder Drittanbieter-Erweiterungen – bis max_fails erreicht ist, können einzelne Anfragen mit 502/504 beim Client landen.
Caching
# im http-Kontext
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=appcache:10m max_size=1g inactive=30m;
# in der proxied location
location / {
proxy_pass http://app_backend;
proxy_cache appcache;
proxy_cache_valid 200 10m;
add_header X-Cache-Status $upstream_cache_status always;
}
X-Cache-Status zeigt im Antwort-Header HIT/MISS/BYPASS – praktisch zur Fehlersuche. Vorsicht: Cache-Keys, Bypass-Regeln und Autorisierung sauber planen, sonst landen personalisierte Antworten (z. B. mit fremden Session-Daten) versehentlich im gemeinsamen Cache.
Rate Limiting
# im http-Kontext: Zone definieren limit_req_zone $binary_remote_addr zone=reqs:10m rate=5r/s; # im server- oder location-Block: anwenden limit_req zone=reqs burst=10 nodelay; limit_req_status 429;
burst=10 nodelay lässt kurze Spitzen bis 10 Anfragen sofort durch, statt sie zu verzögern. Wird die Rate dauerhaft überschritten, antwortet Nginx selbst mit 429 Too Many Requests – das Backend bekommt die Anfrage gar nicht erst zu sehen.
Erweitertes Routing
SPA-Fallback
location / {
try_files $uri $uri/ /index.html;
}
Für Single-Page-Applications: Existiert die angeforderte Datei nicht, liefert Nginx stattdessen index.html aus – das clientseitige Routing im Browser übernimmt den Rest.
Named Location
location / {
try_files $uri @backend;
}
location @backend {
proxy_pass http://127.0.0.1:3000;
}
Eine Named Location (@name) ist nur intern erreichbar, nie direkt über eine URL – praktisch als Fallback-Ziel für try_files.
map-Direktive
map $http_upgrade $connection_upgrade {
default upgrade;
"" close;
}
map erzeugt im http-Kontext eine neue Variable in Abhängigkeit vom Wert einer anderen – hier für den WebSocket-Header Connection genutzt (siehe Abschnitt „Reverse Proxy: proxy_pass und Header“).
Fehlerbilder
| Code | Ursache | Erster Schritt |
|---|---|---|
| 403 | Dateiberechtigungen oder deny all |
Dateirechte/Besitzer prüfen, passende location |
| 404 | falscher root oder falscher Pfad |
root/alias im richtigen location-Block prüfen
|
| 413 | Anfrage größer als client_max_body_size |
Limit gezielt erhöhen, nicht pauschal abschalten |
| 502 | Backend nicht erreichbar oder liefert ungültige Antwort | Backend-Prozess/Port prüfen, error.log lesen
|
| 504 | Backend antwortet, aber zu langsam | proxy_read_timeout prüfen, Backend-Performance klären
|
Nach jeder Config-Änderung zuerst sudo nginx -t, dann erst systemctl reload nginx – ein Syntaxfehler legt sonst beim nächsten Neustart den ganzen Dienst lahm.