Checklist
Load balancer health check checklist
Based on the article: Exchange Server behind F5, Kemp or NetScaler: health checks, SSL and bad-VIP errors · 5 min read
A load balancer in front of Exchange Server only helps if it knows when a protocol on one server is unhealthy, and if it leaves Exchange's authentication intact. In this post I'll set up the parts that matter on any F5 BIG-IP, Kemp LoadMaster or NetScaler: per-protocol health checks, SSL handling that survives Extended Protection, persistence, SMTP and Kerberos, then match the symptoms of a VIP that gets them wrong.
Symptoms to confirm
| What you see | Usual load-balancer cause | First check |
|---|---|---|
HTTP Error 503. The service is unavailable. for some OWA/ECP users | Monitor not on healthcheck.htm, or no receive string, so a server with a failed protocol stays in the pool | Per-server probe test below |
Outlook: The connection to Microsoft Exchange is unavailable. Outlook must be online or connected to complete this action., or Disconnected | MAPI pool down, layer 4 probe on another virtual directory, idle timeout too short | /mapi/healthcheck.htm per server; VIP timeouts (Outlook guide) |
| Password prompts after CU14 or enabling Extended Protection | SSL offloading, or a different certificate on the load balancer | Re-encrypt with the same certificate (Extended Protection) |
| OWA sign-in page keeps returning | Servers behind the VIP have different certificates, so the next server can't read the cookie | Compare thumbprints with Get-ExchangeCertificate |
The Kerberos client received a KRB_AP_ERR_MODIFIED error from the server (System log, Event ID 4) | Namespace SPN on a computer account, no ASA | ASA credential on every server |
550 5.7.54 SMTP; Unable to relay recipient in non-accepted domain for an app | Source NAT hides the app's IP | SMTP receive protocol log |
Checklist
- 1
Namespace and certificate
Publish one namespace (for example
mail.contoso.com) plusautodiscover.contoso.comon the VIP, and set every virtual directory URL to it. Install the same certificate on every server behind the VIP and, if the load balancer terminates TLS, on the load balancer. - 2
One monitor per protocol
Create an HTTPS monitor for each pool:
/owa/healthcheck.htm,/ecp/healthcheck.htm,/ews/healthcheck.htm,/mapi/healthcheck.htm,/Microsoft-Server-ActiveSync/healthcheck.htm,/oab/healthcheck.htm,/autodiscover/healthcheck.htmand/rpc/healthcheck.htmif Outlook Anywhere is still used. Mark a member up only on HTTP 200.Build a custom HTTPS monitor whose Send String is a complete HTTP/1.1 request (HTTP/1.1 requires a Host header):
Send String: GET /owa/healthcheck.htm HTTP/1.1\r\nHost: mail.contoso.com\r\nConnection: Close\r\n\r\n Receive String: 200 OK - 3
Bridge SSL, don't offload it
Extended Protection is on by default from Exchange 2019 CU14, and Microsoft requires SSL offloading for Outlook Anywhere to be disabled.
powershellGet-OutlookAnywhere | Format-Table Server,SSLOffloading -AutoSize # want False - 4
Persistence and timeouts
Leave persistence off; Microsoft notes that affinity reduces load-balancer capacity. Make idle timeouts generous: Outlook, ActiveSync and EWS notifications hold long-lived connections, and a short timeout appears as random disconnects.
- 5
SMTP
If ports 25 or 587 go through the VIP with source NAT, Exchange sees the load balancer's address. Relay connectors that trust
RemoteIPRangescan't identify applications any more: relay fails with 5.7.54, or, if you add the load balancer's IP, everything behind the VIP can relay. - 6
Kerberos
Several servers answering one namespace need an alternate service account (ASA). If the namespace SPN sits on one computer account, clients routed to another server log
KRB_AP_ERR_MODIFIED.
Verify
- Probe every server by IP with your namespace name (use
curl.exe, becausecurlis an alias in Windows PowerShell):
foreach ($ip in "10.0.0.11","10.0.0.12") {
foreach ($v in "owa","ecp","ews","mapi","Microsoft-Server-ActiveSync","oab","autodiscover") {
$code = curl.exe -s -o NUL -w "%{http_code}" --resolve "mail.contoso.com:443:$ip" "https://mail.contoso.com/$v/healthcheck.htm"
"{0,-12} {1,-28} {2}" -f $ip, $v, $code
}
}
Get-ServerComponentState -Identity EX01 | Where-Object { $_.State -ne "Active" }
Get-HealthReport -Identity EX01 | Where-Object { $_.AlertValue -ne "Healthy" }- Good: 200 everywhere, matching the load balancer's member status, no inactive components. Then, in a maintenance window, set
ServerWideOfflinetoInactiveon one server: every monitor should mark it down within a few probe intervals, and come back when you set itActiveagain.
Tips & gotchas
- Probe the servers, not the VIP, and keep probes per pool so one failed protocol doesn't drain the server.
- After renewing the certificate, update the load balancer's copy too when bridging (certificate renewal).
- A component left Inactive after an update looks like a load-balancer fault: the monitors are right to pull the server.
- Read Managed Availability health sets before blaming the appliance for a server it keeps marking down.