RTFM · Load balancing
Internal health checks: what the balancers test natively
Before reaching for external scripts, know what HAProxy and ldirectord can already test by themselves: TCP connects, HTTP requests, protocol greetings, pings. Internal checks are the fast, dependency-free baseline, and the honest boundary where they stop.
Why start internal
An internal check is code inside the balancer itself: no child processes, no script permissions, nothing to install. For "is the port open and is the web server answering HTTP", the built-in probes are the right answer. The discipline is to use them for exactly what they can prove, and nothing more.
The rule both directors follow (and the external library makes explicit) is: a check must fail when its named capability fails. A TCP connect proves a listener exists; it proves nothing about the database behind it. When your promise to users is "the service works", the check must perform the service's own transaction: that is where external checks begin.
HAProxy's built-in checks
backend web
# Layer 4: the plain TCP connect check (default)
server web1 192.168.20.11:80 check
# Layer 7: a real HTTP GET expecting 2xx/3xx
option httpchk GET /healthz
http-check expect status 200
server web1 192.168.20.11:80 check
# Body assertions on the same transaction
http-check expect string "OK"
# TLS backends: upgrade the probe to a TLS handshake
server web1 192.168.20.11:443 check ssl verify none
- TCP connect (check); the kernel accepted our connection. Fastest possible proof that a listener exists.
- HTTP request (option httpchk + http-check expect); status, body substring or regex of a real GET. Understands the web server, not the application's database.
- TLS handshake (check ssl); the backend completes a TLS session, optionally verifying its certificate.
- Agent checks (agent-check); a side channel where the backend reports its own state and weight; powerful, but the backend must speak the agent protocol.
HAProxy's observe layer-and-7 on the actual traffic (on-error / on-marked-down) can complement probes: real users' failures mark a server down without waiting for the next check. It observes; it does not replace the probe.
ldirectord's built-in check types
| checktype | What it does | Honest limits |
|---|---|---|
| connect | Opens a TCP connection to the real server's service port, closes it | Proves a listener; the fallback when richer checks are unavailable (see patch 0002) |
| negotiate | A real protocol conversation per service type: HTTP, HTTPS, LDAP, IMAP, POP, SMTP, MySQL, DNS, RADIUS and more | Depends on optional Perl modules; on Saphira the patched ldirectord degrades missing modules to connect instead of reporting false DOWNs |
| external | Runs checkcommand (your script) with the five standard arguments; exit code is the verdict | The door to the whole Saphira check library, and to anything else you can script |
| ping | ICMP echo to the real server | Layer 3 only: a host can answer ping while every service on it is dead |
| dns | DNS query via Net::DNS | Module-dependent: prefer the external DNS check on Saphira |
| off / on | Administratively hold a real server out (off) or force it in (on) | Maintenance controls, not health checks |
virtual = 203.0.113.10:443
protocol = tcp
scheduler = wlc
real = 192.168.20.11:443 gate
# native TLS-negotiate check
checktype = negotiate
service = https
# same VIP, checked by script instead:
# checktype = external
# checkcommand = "/var/lib/lb/saphira/lb.saphira.tls"
When internal is not enough
- The service speaks a protocol HAProxy does not understand: DICOM, HL7 MLLP, FHIR, RADIUS, SIP, Redis, raw UDP…
- The promise is transactional: "this query returns data", not "this port accepts connections".
- The check needs credentials or per-modality configuration you do not want in the balancer config: the external library resolves settings from environment and admin-owned conf files instead.
- You need the same verdict under both directors: the external $1–$5 ABI is identical for HAProxy and ldirectord.
Did we miss something?
If this page left something unanswered, found an error, or there is another subject you would like documented, tell us. Saphira’s documentation grows from real problems people need to solve.
Send feedback or request a new section →
Prefer not to do it yourself?
Everything needed to do the work yourself is documented here and remains free; we charge for human time, not for withholding knowledge. Sometimes the missing resource is simply time. The same people who build Saphira can provide paid professional help with implementation, migration, troubleshooting and administration.