Skip to content

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.

Saphira Linux dragon mascot

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

HAProxy check vocabulary
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

ldirectord checktype vocabulary
checktypeWhat it doesHonest limits
connectOpens a TCP connection to the real server's service port, closes itProves a listener; the fallback when richer checks are unavailable (see patch 0002)
negotiateA real protocol conversation per service type: HTTP, HTTPS, LDAP, IMAP, POP, SMTP, MySQL, DNS, RADIUS and moreDepends on optional Perl modules; on Saphira the patched ldirectord degrades missing modules to connect instead of reporting false DOWNs
externalRuns checkcommand (your script) with the five standard arguments; exit code is the verdictThe door to the whole Saphira check library, and to anything else you can script
pingICMP echo to the real serverLayer 3 only: a host can answer ping while every service on it is dead
dnsDNS query via Net::DNSModule-dependent: prefer the external DNS check on Saphira
off / onAdministratively hold a real server out (off) or force it in (on)Maintenance controls, not health checks
Native negotiate vs external, side by side
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.

Ask about professional support →