What kind of /health endpoint should I design in my application for health checks?
Short answer
The health endpoint must be fast and lightweight, must not require authentication and must not redirect. While healthy, it must return 200 and a fixed text or JSON; while unhealthy, a non-2xx code such as 503. If the application's dependencies (database, cache) are to be checked, the results must be cached for a short time; strictly checking a dependency shared by all the servers removes all the servers from traffic at the same time when that dependency goes down, and users receive 503. On the TR7 side, the address is defined in the Path + Query field, the expected code in the Expected Status Codes field and the content in the Content Check Mode field.
How Does It Work?
The request that TR7 sends to the server in an HTTP or HTTPS check:
| Property | Value |
|---|---|
| Address | The IP and port of the Backend Service (or the address entered with Use Different IP for Health Check) |
| Path | Path + Query (/ if empty) |
| Method | Method (default GET) |
| User-Agent | tr7-health-check/2.0 (can be changed with HTTP Headers) |
| Host | If Virtual Domain (Host/SNI) is filled in, that name; if it is empty, the server's address |
| Redirect | Not followed; 301/302 is also evaluated as a status code |
| Expected code | By default, only 200 |
| Frequency | At the Period interval (by default, every second); in a cluster, each device checks separately |
| Connection | A new connection in each check (a new TLS connection in HTTPS) |
Design Recommendations
- Fast response: The response is given comfortably below the Timeout in the profile (default 1 s); the body is kept small.
- Clear status code: 200 is returned while healthy, 503 while unhealthy. Returning an error page with 200 in an error situation misleads the check.
- Content: A fixed text (e.g.
OK; upper/lower case matters) or JSON (e.g.{"status":"UP"}) is returned; for JSON, a JSONata expression is used (e.g.body.status = "UP"). - No authentication: If the application definitely requires a key, a header is sent with the HTTP headers field in the profile.
- No redirect: An address that returns 301/302 is counted as failed if these codes are not in the Expected Status Codes list.
- Careful with dependencies: The server's own local dependencies are checked; for shared dependencies, the result is cached or reported only as information.
- Virtual hosting: If the server hosts more than one site on the same IP, the Virtual Domain (Host/SNI) in the profile is filled in (Can I specify a Host / SNI in a health check (Virtual domain)?).
- PROXY protocol: If the server expects the PROXY protocol, the health endpoint is served from a separate port that does not require PROXY, and the check is directed to that port with Use Different IP for Health Check; the health check does not send a PROXY header.
- Logs: The health endpoint is kept on a separate path; in this way, this path is easily excluded from the logs on the web server (Health check requests are filling up my backend logs; what can I do?).
In TR7
- Profile: Load Balancer → Profiles → Health Checks → Add; Check Type HTTP or HTTPS, Path + Query
/health. - Code: In the Expected Status Codes list, 200 (default) is left selected (How do I expect a specific status code (e.g. 200, 302) in an HTTP health check?).
- Content: If Content Check Mode is Basic (string match),
OKis written in the Expected Content Query field; if it is JSONata expression, the expression is written in the JSONata Query field (How do I verify a specific text (e.g. "OK") in the response content?, Can I validate a JSON response field by field in a health check (Content Check Mode: JSONata Expression)?). - Assignment: The profile is selected in the Health Check field of the Backend Service.
Common Misconceptions
- "I use the home page as the health endpoint." The home page can be heavy and can redirect; a separate and lightweight address is recommended.
- "The health endpoint must strictly check all the dependencies." When a shared dependency goes down, all the servers leave traffic at the same time.
- "Returning an error message with 200 in an error situation is enough." The status code must be non-2xx, or a content check must be performed.
How it is done in the documentation
