Hosting · WordPress · performance · infrastructure
explainer

Nginx proxy_next_upstream: Configuring Origin Failover, Time Boundaries, and Non-Idempotent Retries

Short answer

Learn how Nginx proxy_next_upstream manages upstream failover conditions, timeout limits via proxy_next_upstream_timeout, and retry rules for non-idempotent requests.

Research-based

Last verified:

Applies to: NGINX HTTP reverse proxy configuration; documented behavior as retrieved 2026-09-17, with feature-specific version and commercial-subscription limits noted in the article.

Comparison of when NGINX can retry an upstream request

Understanding Origin Failover with Nginx proxy_next_upstream

When operating Nginx as a reverse proxy, handling upstream server failures gracefully is essential for service reliability. The ngx_http_proxy_module provides the proxy_next_upstream directive to define the specific conditions under which an incoming client request should be passed to the next backend server when the current server fails.

By default, Nginx sets proxy_next_upstream error timeout in http, server, and location contexts. Under this default policy, Nginx retries another server only if an error occurs while establishing a connection with the server, passing a request to it, or reading the response header, or if a corresponding timeout occurs.

Conditions That Trigger Failover

The proxy_next_upstream directive accepts specific failure conditions, as well as an explicit off parameter to disable passing a request to the next server entirely:

  • error: An error occurred while establishing a connection with the server, passing a request to it, or reading the response header. (Always considered an unsuccessful attempt).
  • timeout: A timeout occurred while establishing a connection with the server, passing a request to it, or reading the response header. (Always considered an unsuccessful attempt).
  • invalid_header: A server returned an empty or invalid response. (Always considered an unsuccessful attempt).
  • denied: The server denied the connection (annotated as appearing in version 1.29.3 as part of commercial subscription features; always considered an unsuccessful attempt).
  • HTTP Status Codes: http_500, http_502, http_503, http_504, and http_429 (with http_429 annotated as appearing in version 1.11.13). These status codes are considered unsuccessful attempts only if explicitly specified in the directive.
  • Excluded Status Codes: http_403 and http_404 are never considered unsuccessful attempts.

How an attempt is classified also directly affects upstream server availability tracking. Under the ngx_http_upstream_module, each upstream server entry can define max_fails (defaulting to 1) and fail_timeout (defaulting to 10 seconds). What counts as an unsuccessful attempt is defined by directives including proxy_next_upstream. An attempt counted as unsuccessful contributes toward the server’s max_fails threshold within the fail_timeout duration to consider the server unavailable for that duration. If there is only a single server in an upstream group, max_fails and fail_timeout are ignored, and that server is never considered unavailable.

Limiting Retries: Time Boundaries and Tries

The documentation states that passing a request to the next server can be limited by the number of tries and by time.

For time limits, Nginx provides the proxy_next_upstream_timeout directive:

  • proxy_next_upstream_timeout time; (Default: proxy_next_upstream_timeout 0;): Configured in http, server, and location contexts. Documented as appearing in version 1.7.5.

The Response Transfer Limitation and Buffering

A crucial operational boundary governs passing requests to the next server: passing a request to the next server is only possible if nothing has been sent to a client yet. If an error or timeout occurs in the middle of transferring a response, fixing this is impossible.

In addition, response buffering settings affect how response data is delivered:

  • Under proxy_buffering on; (the default), Nginx receives a response from the proxied server as soon as possible, saving it into the buffers configured by proxy_buffer_size and proxy_buffers. If the whole response does not fit into memory, a part of it can be saved to a temporary file via proxy_max_temp_file_size and proxy_temp_file_write_size.
  • When proxy_buffering off; is set, the response is passed to a client synchronously, immediately as it is received, and Nginx will not try to read the whole response from the proxied server.

Handling Non-Idempotent Requests

Normally, requests with a non-idempotent method (POST, LOCK, PATCH) are not passed to the next server if a request has already been sent to an upstream server (annotated as appearing in version 1.9.13). Enabling the non_idempotent option in proxy_next_upstream explicitly allows retrying such requests.

Configuration Example

The following example demonstrates specifying failure triggers and setting a retry timeout window in an Nginx configuration:

upstream backend_cluster {
    server 10.0.0.1:8080 max_fails=2 fail_timeout=10s;
    server 10.0.0.2:8080 max_fails=2 fail_timeout=10s;
}

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://backend_cluster;
        proxy_buffering on;

        # Failover triggers
        proxy_next_upstream error timeout http_502 http_503;

        # Limit retry time window
        proxy_next_upstream_timeout 5s;
    }
}
Comparison of NGINX failover and upstream availability controls

Text version of the diagrams

  • When NGINX Can Retry: Before response — Another upstream may be tried; Client receives data — Retry is no longer possible; Non-idempotent — Retry requires explicit option
  • Three Failover Controls: Conditions — Choose errors or statuses; Timeout window — Limit total retry time; Server tracking — max_fails and fail_timeout

Research Method and Limitations

This technical explainer was prepared exclusively from the supplied public documentation excerpts for ngx_http_proxy_module and ngx_http_upstream_module. Competing community coverage from DigitalOcean was unavailable because the retrieved excerpt contained only site navigation. A precise global Nginx version scope cannot be asserted across all described behaviors; the supplied excerpts provide only point-in-time reference text with specific version annotations noted for individual features (such as proxy_next_upstream_timeout in 1.7.5, non_idempotent in 1.9.13, http_429 in 1.11.13, and denied in 1.29.3 under commercial subscription). Furthermore, while the documentation notes that passing requests to the next server can be limited by the number of tries, the specific directive syntax and defaults for tries limits were omitted in the supplied excerpts and are excluded here.

Related guides