Was zwischen Browser und Ihrer App steht
Rufen Sie im Browser example.com auf, erreicht die Anfrage nie direkt den Prozess, der Ihren Code ausführt. Sie trifft zuerst auf etwas anderes: einen Server, der die Anfrage liest, entscheidet, welches Backend antworten soll, sie dorthin weiterleitet und die Antwort zurückschickt, als hätte er sie selbst erzeugt. Dieser Server ist ein Reverse Proxy.
Nginx, Caddy, Traefik und HAProxy übernehmen alle diese Aufgabe, ebenso der Load Balancer vor einem Kubernetes-Cluster. Das Grundmuster ändert sich nie: Clients sprechen nur mit dem Proxy, mit sonst nichts. Die eigentlichen Server bleiben dahinter, egal wie viele es sind und wo sie laufen.
Wie ein Reverse Proxy eine Anfrage verarbeitet
Ein Client öffnet eine Verbindung zur IP und zum Port des Reverse Proxys, genau wie zu jedem anderen Server. Der Proxy terminiert diese Verbindung, liest die Anfragezeile und die Header und gleicht sie mit den eigenen Regeln ab — meist dem Host-Header und dem URL-Pfad. Anhand dieses Abgleichs öffnet er eine zweite, separate Verbindung zu einem Backend, leitet die Anfrage darüber weiter, wartet auf die Antwort und gibt sie über die ursprüngliche Verbindung des Clients zurück.
Zwei unabhängige Verbindungen, aneinandergenäht. Aus Sicht des Clients ist das nicht davon zu unterscheiden, direkt mit dem Backend zu sprechen. Aus Sicht des Backends scheint jede Anfrage von einer einzigen Maschine zu kommen, dem Proxy, statt aus dem Internet allgemein.
| |
Weil der Proxy jede Anfrage sieht, bevor das Backend sie erreicht, kann er sie prüfen, verändern, cachen oder ablehnen. Genau diese Position sorgt dafür, dass er am Ende die Arbeit übernimmt, die niemand in der Anwendung selbst haben will: TLS terminieren, Antworten komprimieren, statische Inhalte cachen, missbräuchliche Clients drosseln und unterschiedliche Pfade an unterschiedliche Dienste schicken — /api an ein Backend, / an ein anderes, /static direkt von der Platte.
Reverse Proxy vs. Forward Proxy
Beide sitzen mitten in einer Verbindung. Der Unterschied liegt darin, für wen sie arbeiten.
| Forward Proxy | Reverse Proxy | |
|---|---|---|
| Handelt im Auftrag von | Dem Client | Dem Server |
| Client weiß, dass er existiert | Meist ja (explizit konfiguriert) | Nein (sieht aus wie der echte Server) |
| Was er verbirgt | Die Identität des Clients vor dem Server | Die Identität des Servers vor dem Client |
| Typische Nutzung | Ausgehende Filterung im Unternehmen, Umgehen von Geoblocking, anonymes Surfen | Routing, TLS-Terminierung, Caching, Schutz der Origin-Server |
Ein Forward Proxy ist die Box, die der Arbeitgeber im Büro aufstellt, damit der gesamte ausgehende Traffic über einen einzigen, gefilterten Punkt läuft: Die Website, die Sie besuchen, protokolliert die Adresse des Proxys, nicht die Ihres Laptops. Einen Reverse Proxy betreiben die Betreiber der Website selbst, und er verbirgt das andere Ende. Von außen lässt sich nicht sagen, ob hinter example.com ein Server steckt oder vierzig.
Reverse Proxy vs. Load Balancer
Die beiden Begriffe werden häufig synonym verwendet, vor allem weil ein einzelner Nginx- oder HAProxy-Prozess meist beide Aufgaben gleichzeitig übernimmt.
| Reverse Proxy | Load Balancer | |
|---|---|---|
| Zentrale Frage, die er beantwortet | Was soll mit dieser Anfrage passieren? | Welcher Server soll diese Anfrage bearbeiten? |
| Funktioniert mit einem einzigen Backend? | Ja, bleibt nützlich (TLS, Caching, Routing nach Pfad) | Nein, braucht mindestens zwei zum Verteilen |
| Typische Zusatzfunktionen | Caching, Header-Umschreibung, TLS-Terminierung, Pfad-Routing | Health-Checks, gewichtete Verteilung, Session-Affinität |
Ein Reverse Proxy vor einem einzigen Backend lohnt sich trotzdem: Er terminiert das TLS, damit Ihre App das nicht tun muss, verbirgt die echte Adresse des Backends, fügt gzip hinzu. Ein Load Balancer hat nichts zu tun, solange nicht mindestens zwei Backends zur Auswahl stehen. Welche Bezeichnung Sie verwenden, beschreibt also die geschriebene Konfiguration, nicht die installierte Software.
Nginx als Reverse Proxy konfigurieren
Auf einem Port lauschen, einen Hostnamen abgleichen, an ein Backend weiterleiten. Das ist bereits das gesamte Minimum:
| |
proxy_pass ist die entscheidende Zeile: Alles, was location erfasst, geht an http://127.0.0.1:3000. Die vier proxy_set_header-Zeilen sind nötig, weil das Backend sonst den Proxy als Client sieht und jede Anfrage so aussieht, als käme sie von 127.0.0.1. X-Real-IP und X-Forwarded-For transportieren die echte Client-Adresse weiter. X-Forwarded-Proto teilt dem Backend mit, ob die ursprüngliche Anfrage über HTTPS kam, da das TLS am Proxy terminiert wurde und der nächste Hop reines HTTP ist.
Ein Detail bringt Setups ständig durcheinander: Ein abschließender Schrägstrich in der proxy_pass-URI verändert den weitergeleiteten Pfad. proxy_pass http://backend; (ohne Pfad) leitet die ursprüngliche URI unverändert weiter. proxy_pass http://backend/; (mit abschließendem Schrägstrich) entfernt vor dem Weiterleiten den Teil der URI, den location erfasst hat. Bei location /api/ und proxy_pass http://backend/; kommt eine Anfrage an /api/users beim Backend als /users an. Vertauschen Sie das, liefert jede Route beim Backend ein 404, während curl gegen den Proxy einwandfrei aussieht.
Reverse Proxy vor einer Dockerisierten App
Genau hier taucht das Muster im Alltag am häufigsten auf: Nginx in einem Container, Ihre App in einem anderen, beide im selben Docker-Netzwerk, damit Nginx die App über den Containernamen erreicht — das DNS-Verhalten, das in was ein Docker-Netzwerk bietet beschrieben ist.
| |
| |
app gibt Port 3000 im Compose-Netzwerk frei, veröffentlicht aber nichts auf dem Host. Das erledigt allein Nginx, auf Port 80. Der Name app:3000 in der Nginx-Konfiguration wird über das interne DNS von Docker aufgelöst, denselben Mechanismus, der im Docker-Compose-Guide beschrieben ist. Mit docker compose up landen Anfragen an localhost bei Nginx, das sie in den App-Container weiterleitet. Die App ist allein von außerhalb des Hosts nie erreichbar — das ist ebenso beabsichtigt wie das Routing selbst.
Was ein Reverse Proxy kostet
Er fügt einen zusätzlichen Netzwerk-Hop hinzu und eine weitere Stelle, an der eine Anfrage scheitern kann. Ein falsch konfiguriertes proxy_pass oder ein verlorener Header zeigt sich als Bug in der App, obwohl der Fehler eine Ebene weiter vorn liegt. Er ist außerdem standardmäßig ein Single Point of Failure: Beenden Sie den einen Nginx-Prozess, wird jedes Backend dahinter unerreichbar. Produktionsumgebungen betreiben ihn entweder redundant oder übergeben die Aufgabe an etwas, das Ausfälle bereits einkalkuliert — einen Cloud-Load-Balancer oder einen Kubernetes-Ingress-Controller, der auf den darunterliegenden Deployments und Pods aufbaut.
Ein Reverse Proxy macht eine App auch nicht von allein schneller oder skalierbarer. Er kann cachen und komprimieren, aber ein langsames Backend bleibt langsam; der Proxy leitet diese Langsamkeit nur einen Hop später weiter. Und er ist weder Authentifizierung noch Eingabevalidierung. Offensichtlich fehlerhafte Anfragen schon am Rand abzublocken ist ein Bonus, niemals ein Grund dafür, dass die App aufhört, das Empfangene zu prüfen.
Diese Konfiguration in Produktion überführen
Nehmen Sie das compose.yaml von oben, ersetzen Sie app durch einen echten Dienst und fügen Sie ssl_certificate sowie ssl_certificate_key zum server-Block von Nginx hinzu, sobald Sie ein Zertifikat haben. Das ist der Unterschied zwischen einer lokalen Übung und etwas, das Sie vor echten Traffic stellen würden. Routen Sie zu mehr als einem Backend, ersetzen Sie die einzelne Adresse durch einen upstream-Block mit mehreren server-Zeilen und lassen Sie proxy_pass auf diesen Block zeigen: Dieselbe Konfiguration wird damit zu einem Load Balancer.