oeltayeb.com · Exchange Server Troubleshooting Toolkit

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 seeUsual load-balancer causeFirst check
HTTP Error 503. The service is unavailable. for some OWA/ECP usersMonitor not on healthcheck.htm, or no receive string, so a server with a failed protocol stays in the poolPer-server probe test below
Outlook: The connection to Microsoft Exchange is unavailable. Outlook must be online or connected to complete this action., or DisconnectedMAPI 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 ProtectionSSL offloading, or a different certificate on the load balancerRe-encrypt with the same certificate (Extended Protection)
OWA sign-in page keeps returningServers behind the VIP have different certificates, so the next server can't read the cookieCompare 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 ASAASA credential on every server
550 5.7.54 SMTP; Unable to relay recipient in non-accepted domain for an appSource NAT hides the app's IPSMTP receive protocol log

Checklist

  1. 1

    Namespace and certificate

    Publish one namespace (for example mail.contoso.com) plus autodiscover.contoso.com on 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. 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.htm and /rpc/healthcheck.htm if 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. 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.

    powershell
    Get-OutlookAnywhere | Format-Table Server,SSLOffloading -AutoSize   # want False
  4. 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. 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 RemoteIPRanges can'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. 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, because curl is an alias in Windows PowerShell):
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 ServerWideOffline to Inactive on one server: every monitor should mark it down within a few probe intervals, and come back when you set it Active again.

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.

Microsoft Learn references