Nginx · The edge of your stack

How do health checks work with Nginx upstreams?

Hardhealth checksupstreamfailoverUpdated Oct 2026
Quiz this track

Short answer

Open-source Nginx uses passive checks: max_fails and fail_timeout eject a failing server after real request failures. Active health checks with health_check are an Nginx Plus feature, so open-source setups often use an external orchestrator or load balancer.

Passive checks react to traffic. A server is marked unavailable after max_fails failures inside fail_timeout, then retried after that window. The first failed request may still reach a client, so retries and idempotency matter.

nginx
upstream app {
    server 10.0.0.11:8080 max_fails=3 fail_timeout=10s;
    server 10.0.0.12:8080 max_fails=3 fail_timeout=10s;
    server 10.0.0.13:8080 backup;
}

server {
    location /healthz {
        access_log off;
        proxy_pass http://app;
    }
}
The healthz endpoint can be probed by an external load balancer or orchestrator.

Active versus passive

  • Passive checks use real traffic and need no extra requests
  • Active checks probe every backend on a schedule and remove failures faster
  • The open-source health_check directive is not available; it requires Nginx Plus
  • Kubernetes readiness probes, Consul or a cloud load balancer can provide active checks
  • Health endpoints should test process health, not every downstream dependency
A health check that requires the database can take every instance out during a shared dependency outage. Separate liveness from readiness and keep the check cheap.

Follow-ups you should expect

Interviewers use these to check whether the first answer was understanding or memorisation.

  1. 1What is the difference between active and passive health checks?
  2. 2Why can a dead backend still receive one request?
  3. 3How do readiness and liveness differ?
  4. 4How would you remove a backend without editing the main config?

Say it in the interview

Open-source Nginx health checking is passive: it uses max_fails and fail_timeout based on real requests. A failing backend can still receive the request that triggers ejection, so I use retries and idempotent operations. For active checks I rely on the orchestrator, a cloud load balancer or Nginx Plus. I keep health endpoints cheap and separate readiness from deep dependency checks.

Use this as a model, not a script. Saying it in your own words is what makes it survive follow-up pressure.

Related questions

Reading is step one

Now say it out loud.

Understanding an answer and delivering it under pressure are different skills. Rehearse this topic in a live Nginx mock interview and get scored feedback on depth, clarity and confidence.