Bei einem Nginx-Reverse-Proxy entscheidet die Wartezeit auf den Upstream oft darüber, ob ein Request sauber endet oder nach 60 Sekunden mit einem 504 abbricht. Ich zeige hier, was die Nginx-Direktive proxy_read_timeout wirklich misst, wie sie sich von den anderen Proxy-Timeouts unterscheidet und welche Werte in der Praxis sinnvoll sind. Außerdem geht es darum, wann ein höherer Wert hilft und wann er nur ein langsames Backend verdeckt.
Die wichtigsten Punkte auf einen Blick
-
proxy_read_timeoutlegt fest, wie lange Nginx zwischen zwei Lesevorgängen auf Daten vom Upstream wartet. - Der Standardwert liegt bei 60s; die Zeit gilt nicht für die gesamte Antwort, sondern für die Pause zwischen Datenblöcken.
- Der Wert gehört meist in den passenden
location-Block, nicht pauschal global in jede Konfiguration. - Ein 504 ist oft ein Symptom, nicht die eigentliche Ursache. Häufig steckt ein langsamer Datenbankaufruf, ein blockierter Worker oder ein zu träger Dienst dahinter.
- Für WebSockets und Streaming reicht ein hoher Wert allein nicht aus. Die Anwendung sollte zusätzlich regelmäßig Daten oder Heartbeats senden.

Was die Lesezeit im Proxy-Modus wirklich bedeutet
Ich lese die Direktive so: Nginx wartet nicht auf die komplette Antwort als einen großen Block, sondern auf den nächsten Datenimpuls vom Upstream. Standard sind 60 Sekunden, und die Zeit läuft nicht während der gesamten Übertragung, sondern nur zwischen zwei erfolgreichen Leseoperationen. Kommt in diesem Fenster nichts an, schließt Nginx die Verbindung.
Das ist wichtig, weil eine langsame, aber stetige Antwort trotzdem durchkommen kann. Ein Export, der alle 20 Sekunden einen Chunk liefert, läuft also auch dann weiter, wenn die komplette Datei erst nach zehn Minuten fertig ist. Umgekehrt reicht schon eine längere Denkpause im Backend, etwa bei einer teuren Datenbankabfrage oder einem blockierten Worker, um den Timeout auszulösen.
Die Direktive lässt sich im http-, server- oder location-Block setzen. Ich nutze sie fast immer dort, wo die Ausnahme sitzt, nicht pauschal global. Nginx akzeptiert dabei Zeiteinheiten wie 90s, 5m oder 1h 30m.
location /api/ {
proxy_pass http://app_backend;
proxy_read_timeout 90s;
}Wichtig ist auch: Ob Antworten gepuffert werden oder direkt weitergehen, ändert die Bedeutung der Wartezeit nicht. Entscheidend bleibt, ob der Upstream rechtzeitig Daten liefert. Damit ist die semantische Falle geklärt, und als Nächstes lohnt sich der Blick auf die Symptome im Fehlerfall.
Woran man ein zu knappes Timeout erkennt
In der Praxis sehe ich drei typische Muster. Erstens: Der Client meldet einen 504 Gateway Timeout, obwohl die Anwendung lokal noch arbeitet. Zweitens: Im Error Log erscheint ein Hinweis, dass Nginx beim Lesen der Upstream-Antwort zu lange gewartet hat. Drittens: Das Problem tritt nur bei bestimmten Endpunkten auf, meist dort, wo wirklich Arbeit passiert.
- Berichte, Exporte und PDF-Generierung laufen aus dem Ruder.
- Login- oder Checkout-Flows hängen an einer langsamen externen API.
- Große Uploads oder synchron verarbeitete Jobs blockieren zu lange.
- Lastspitzen, Datenbank-Locks oder ein Neustart des Backends machen das Verhalten sporadisch.
Der wichtige Punkt ist: Nicht jeder 504 kommt aus derselben Ecke. Wenn die Verbindung schon beim Aufbau scheitert, ist eher der Verbindungs-Timeout beteiligt. Wenn das Senden der Anfrage stockt, liegt der Fehler eher bei der Gegenrichtung. Wenn aber die Antwort einfach still bleibt, ist der Read-Timeout der naheliegende Kandidat. Genau diese Trennung spart im Debugging viel Zeit, und sie führt direkt zur Frage, welche Werte in der Praxis wirklich sinnvoll sind.
So setze ich sinnvolle Werte in der Praxis
Wenn ich den Wert anpasse, arbeite ich fast nie nach Bauchgefühl. Ich nehme den tatsächlichen Use Case, schaue auf die längste sinnvolle Backend-Pause und setze dann einen Wert mit etwas Luft nach oben. Als grobe Praxisregel starte ich meist mit 60 Sekunden für normale APIs, 120 bis 300 Sekunden für rechenintensive Exporte und deutlich höheren Werten nur für Verbindungen, die bewusst lange offen bleiben sollen.
Das sind Startwerte, keine Garantien. Eine langsam wachsende Antwort ist etwas anderes als ein endpoint, der eigentlich anders gebaut werden sollte. Wenn ein Prozess regelmäßig mehrere Minuten braucht, ist asynchrones Arbeiten oft sauberer als einfach mehr Wartezeit zu erlauben.
| Einsatz | Startwert | Warum so | Mein Hinweis |
|---|---|---|---|
| Normale API-Endpunkte | 30s bis 60s | Antworten sollten hier meist schnell kommen. | Wenn das nicht reicht, prüfe ich zuerst Querys, Cache und App-Logik. |
| Reports und Exporte | 120s bis 300s | Diese Jobs dürfen länger rechnen, brauchen aber einen klar abgegrenzten Pfad. | Ich setze den Wert nur für den Export-Endpunkt, nicht global. |
| Batch-Jobs und Imports | 300s oder mehr | Hier ist die Antwortphase oft ungleichmäßiger. | Oft ist eine asynchrone Verarbeitung robuster als ein sehr hoher Timeout. |
| WebSocket- oder Streaming-Verbindungen | 1h oder mehr | Die Verbindung soll bewusst lange offen bleiben. | Nur sinnvoll, wenn die Anwendung Heartbeats oder Ping-Frames sendet. |
Ich erhöhe den Wert nur dort, wo das Verhalten fachlich begründet ist. Ein pauschal hoher Wert in der gesamten Instanz macht Fehler später sichtbar, bindet Verbindungen länger und kaschiert gern Probleme, die eigentlich im Backend gelöst werden sollten. Sobald das sauber eingeordnet ist, lohnt sich die Abgrenzung zu den anderen Proxy-Timeouts.
Der Unterschied zu Verbindungs- und Sendetimeout
Die drei Direktiven werden regelmäßig verwechselt, weil alle mit denselben 60 Sekunden starten. Inhaltlich decken sie aber unterschiedliche Phasen ab: verbinden, Anfrage senden und Antwort lesen. Wer die falsche Phase verändert, optimiert am eigentlichen Problem vorbei.
| Direktive | Was sie steuert | Standard | Typischer Irrtum |
|---|---|---|---|
proxy_connect_timeout |
Aufbau der Verbindung zum Upstream | 60s | Wird oft fälschlich für die Antwortzeit gehalten. |
proxy_send_timeout |
Senden der Anfrage an den Upstream | 60s | Wichtig bei Uploads und langsamen Gegenstellen. |
proxy_read_timeout |
Warten auf Daten aus der Antwort | 60s | Gilt nicht für die komplette Antwort, sondern zwischen zwei Lesevorgängen. |
Beim Verbindungsaufbau gilt zusätzlich: proxy_connect_timeout ist ein anderer Mechanismus und überschreitet in der Regel nicht 75 Sekunden. Ich merke mir die Reihenfolge so: erst verbinden, dann Anfrage senden, dann Antwort lesen. Gerade bei Uploads oder langsamen TLS-Verbindungen spart diese Abgrenzung viel Zeit im Debugging. Wenn diese Trennung sitzt, wird der Sonderfall für lange Verbindungen deutlich leichter zu bewerten.
Was bei WebSockets, Long Polling und Streaming anders ist
Bei langen Verbindungen ist nicht die Gesamtlaufzeit das Problem, sondern die Funkstille. Nginx erwartet auch hier, dass der Upstream innerhalb des gewählten Fensters Daten schickt. Die 60-Sekunden-Grenze lässt sich erhöhen, aber in der Praxis setze ich zusätzlich auf Heartbeats oder Ping-Frames aus der Anwendung.
- Bei WebSockets sollten Server regelmäßig Ping-Frames senden, wenn längere Ruhephasen möglich sind.
- Bei Server-Sent Events helfen kleine Heartbeat-Events oder Kommentarzeilen, damit die Verbindung nicht als still erscheint.
- Bei Long Polling muss das Backend sauber zwischen echter Wartezeit und Blockade unterscheiden.
- Bei Stream-Downloads ist Chunking oft robuster als ein einzelner großer Response-Block.
location /chat/ {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 1h;
}Der entscheidende Punkt ist: Ein hoher Timeout ersetzt keine Lebenszeichen aus dem Backend. Wenn die Verbindung wirklich offen bleiben soll, muss die Anwendung selbst dafür sorgen, dass sie nicht stillsteht. Genau dort liegt der Unterschied zwischen einer sauberen Dauerverbindung und einem bloß verlängerten Warten.
Welche Stellschrauben ich vor einem höheren Timeout prüfe
Bevor ich den Wert einfach hochdrehe, prüfe ich immer die Ursache hinter der Verzögerung. Oft ist der Proxy nur der Ort, an dem das eigentliche Problem sichtbar wird.
- Lange SQL-Abfragen oder fehlende Indizes.
- Sync-Calls zu externen APIs, die besser asynchron laufen sollten.
- Zu wenig Worker, CPU-Druck oder Speicherengpässe im Backend.
- Falsche Cache-Strategie, obwohl die Antwort eigentlich selten wechselt.
- Zu grob gewählte globale Werte statt enger, pfadspezifischer Regeln.
Wenn ich den Timeout doch erhöhe, tue ich das bewusst begrenzt: nur für den betroffenen Pfad, nur so hoch wie nötig und mit Monitoring für 504er, Antwortzeiten und Upstream-Auslastung. So bleibt Nginx ein Schutzschild und wird nicht zur unsichtbaren Warteschlange für eine überlastete Anwendung.