How To Load Balance Exchange Services Using HAProxy
If you have Microsoft Exchange Servers configured in a database availability group (DAG) you almost have a highly available Exchange setup. The last, tricky part is to load balance the Exchange Services over your Exchange cluster. For example, at the moment you are likely using Autodiscovery on a single host. If that host goes down, new accounts won’t pick up the redundant Autodiscovery URL for the redundant servers, causing that service to fail. We can configure HAProxy to Exchange 2019
There are several solutions to load balance like Kemp and HAproxy. We are using HAproxy because it’s lightweight, extremely stable and checks all of the boxes feature-wise. The server this runs off must be a High Availability Server. That means it needs to be running on a Cloud or other H/A platform. Our Load Balancer for this configuration is deployed to outlook.f2h.cloud running Ubuntu 22 LTS. It’s powered by a 2 vCores, 2GB RAM, 25GB HDD on NVMe hardware with two failover regions enabled.
Install HAProxy For Exchange 2019
Install HAProxy with the default commands below, updating the server before the installation.
apt-get update
apt-get upgrade -y
add-apt-repository ppa:vbernat/haproxy-2.5
apt update apt install haproxy
Configure HAProxy to Load balance Exchange 2019 Services
This is going to take some time. We need to create a backend for each Exchange Service we want to load balance. So let’s get started. First, delete or move the default configuration file. We’re going to create our own block by block. This assumes you also have an SSL installed on the server. We are using a Cloudflare Origin Certificate and the certificate is located on the HAProxy server at /etc/ssl/cert.pem.
rm /etc/haproxy/haproxy.cfg
Now, create a new haproxy.cfg file and let’s start editing.
nano /etc/haproxy/haproxy.cfg
Default HAProxy Block
And in this block, there isn’t much that needs to be edited. The default values should be perfect for Exchange. The only things you need to change are towards the bottom. So specify the IP of the HAProxy server and a username and password to access the statistics page.
bind IPV4:1936 ssl crt /etc/ssl/cert.pem
Copy and paste the below block to the haproxy.cfg file. We’ve commented on the HAProxy configuration below.
global
log 127.0.0.1 local2 info
chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
user haproxy
group haproxy
daemon
# turn on stats unix socket
stats socket /var/run/haproxy.stat
#--------------------------
# SSL tuning / hardening
#--------------------------
ssl-default-bind-options no-sslv3
ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS
ssl-default-server-options no-sslv3
ssl-default-server-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS
tune.ssl.default-dh-param 2048
#---------------------------------------------------------------------
# common defaults that all the 'listen' and 'backend' sections will
# use if not designated in their block
#---------------------------------------------------------------------
# Regarding timeout client and timeout server:
# https://discourse.haproxy.org/t/high-number-of-connection-resets-during-transfers-exchange-2013/1158/4
defaults
mode http
log global
option httplog
option dontlognull
option forwardfor except 127.0.0.0/8
option redispatch
# option contstats
retries 3
timeout http-request 10s
timeout queue 1m
timeout connect 10s
timeout client 15m # this value should be rather high with Exchange
timeout server 15m # this value should be rather high with Exchange
timeout http-keep-alive 10s
timeout check 10s
maxconn 100000
#-------------------------------------------------------
# Stats section
#-------------------------------------------------------
# Change the bind line to reflect the HAProxy IPv4. Also specify the path to the SSL for the
# balancer. This allows access to the stats page. If you want to access the stats at a different
# location edit the stats uri line. https://ipv4/haproxy?stats.
listen stats
bind IPV4:1936 ssl crt /etc/ssl/cert.pem
mode http
stats enable
stats hide-version
stats show-node
stats realm Haproxy\ Statistics
stats uri /haproxy?stats
stats admin if TRUE
stats auth User:Pass
Frontend HAProxy Configuration Block
Now we need to configure the frontend sections. This is how the Exchange 2019 load balancer will deal with Exchange connections. Copy the following block to the haproxy.cfg file. In this section, you need to specify the HAPoxy Exchange 2019 servers IPv4 and correct the location of the SSL if required. Usually this is the same SSL as you specified in the first block.
Don’t forget to update the A record on your balancer name. Our A record for outlook.f2h.cloud would point to the IPv4 of the balancer.
bind IPv4:80
bind IPv4:443 ssl crt /etc/ssl/cert.pem
#---------------------------------------------------------------------
# Main front-end which proxies to the back-ends
#---------------------------------------------------------------------
frontend ft_ex2019
# http-response set-header Strict-Transport-Security max-age=31536000;\ includeSubdomains;\ preload
http-response set-header X-Frame-Options SAMEORIGIN
http-response set-header X-Content-Type-Options nosniff
mode http
bind IPv4:80
bind IPv4:443 ssl crt /etc/ssl/cert.pem
redirect scheme https code 301 if !{ ssl_fc } # redirect 80 -> 443 (for owa)
acl autodiscover url_beg /Autodiscover
acl autodiscover url_beg /autodiscover
acl mapi url_beg /mapi
acl rpc url_beg /rpc
acl owa url_beg /owa
acl owa url_beg /OWA
acl eas url_beg /Microsoft-Server-ActiveSync
acl ecp url_beg /ecp
acl ews url_beg /EWS
acl ews url_beg /ews
acl oab url_beg /OAB
use_backend bk_ex2019_autodiscover if autodiscover
use_backend bk_ex2019_mapi if mapi
use_backend bk_ex2019_rpc if rpc
use_backend bk_ex2019_owa if owa
use_backend bk_ex2019_eas if eas
use_backend bk_ex2019_ecp if ecp
use_backend bk_ex2019_ews if ews
use_backend bk_ex2019_oab if oab
default_backend bk_ex2019
You can see we are using acl’s to route the services the load balancer will deal with and then sending those connections to the backend servers which we will do next.
Backend HAProxy Configuration Blocks
In this section, we will configure where the load balancer will send the Exchange connections two. We have two Exchange servers configured in our DAG. The important bit to notice here is the SSL certificates that are currently installed on our Exchange servers. These need to be copied to the Load Balancer. Ours are located at /etc/ssl/exchange1 and /etc/ssl/exchange2. Update the IPv4 for the IPv4 of your Exchange Servers
#------------------------------
# Back-end section
#------------------------------
backend bk_ex2019_autodiscover
mode http
balance roundrobin
option httpchk GET /autodiscover/healthcheck.htm
option log-health-checks
http-check expect status 200
server exchange1 IPv4:443 check ssl inter 15s verify required ca-file /etc/ssl/exchange1/exchange.ca-bundle
server exchange2 IPv4:443 check ssl inter 15s verify required ca-file /etc/ssl/exchange2/exchange-1.ca-bundle
backend bk_ex2019_mapi
mode http
balance roundrobin
option httpchk GET /mapi/healthcheck.htm
option log-health-checks
http-check expect status 200
server exchange1 IPv4:443 check ssl inter 15s verify required ca-file /etc/ssl/exchange1/exchange.ca-bundle
server exchange2 IPv4:443 check ssl inter 15s verify required ca-file /etc/ssl/exchange2/exchange-1.ca-bundle
backend bk_ex2019_rpc
mode http
balance roundrobin
option httpchk GET /rpc/healthcheck.htm
option log-health-checks
http-check expect status 200
server exchange1 IPv4:443 check ssl inter 15s verify required ca-file /etc/ssl/exchange1/exchange.ca-bundle
server exchange2 IPv4:443 check ssl inter 15s verify required ca-file /etc/ssl/exchange2/exchange-1.ca-bundle
backend bk_ex2019_owa
mode http
balance roundrobin
option httpchk GET /owa/healthcheck.htm
option log-health-checks
http-check expect status 200
server exchange1 IPv4:443 check ssl inter 15s verify required ca-file /etc/ssl/exchange1/exchange.ca-bundle
server exchange2 IPv4:443 check ssl inter 15s verify required ca-file /etc/ssl/exchange2/exchange-1.ca-bundle
backend bk_ex2019_eas
mode http
balance roundrobin
option httpchk GET /microsoft-server-activesync/healthcheck.htm
option log-health-checks
http-check expect status 200
server exchange1 IPv4:443 check ssl inter 15s verify required ca-file /etc/ssl/exchange1/exchange.ca-bundle
server exchange2 IPv4:443 check ssl inter 15s verify required ca-file /etc/ssl/exchange2/exchange-1.ca-bundle
backend bk_ex2019_ecp
mode http
balance roundrobin
option httpchk GET /ecp/healthcheck.htm
option log-health-checks
http-check expect status 200
server exchange1 IPv4:443 check ssl inter 15s verify required ca-file /etc/ssl/exchange1/exchange.ca-bundle
server exchange2 IPv4:443 check ssl inter 15s verify required ca-file /etc/ssl/exchange2/exchange-1.ca-bundle
backend bk_ex2019_ews
mode http
balance roundrobin
option httpchk GET /ews/healthcheck.htm
option log-health-checks
http-check expect status 200
server exchange1 IPv4:443 check ssl inter 15s verify required ca-file /etc/ssl/exchange1/exchange.ca-bundle
server exchange2 IPv4:443 check ssl inter 15s verify required ca-file /etc/ssl/exchange2/exchange-1.ca-bundle
backend bk_ex2019_oab
mode http
balance roundrobin
option httpchk GET /oab/healthcheck.htm
option log-health-checks
http-check expect status 200
server exchange1 IPv4:443 check ssl inter 15s verify required ca-file /etc/ssl/exchange1/exchange.ca-bundle
server exchange2 IPv4:443 check ssl inter 15s verify required ca-file /etc/ssl/exchange2/exchange-1.ca-bundle
backend bk_ex2019
mode http
balance roundrobin
server exchange1 IPv4:443 check ssl inter 15s verify required ca-file /etc/ssl/exchange1/exchange.ca-bundle
server exchange2 IPv4:443 check ssl inter 15s verify required ca-file /etc/ssl/exchange2/exchange-1.ca-bundle
Load Balance Exchange SMTP & IMAP Services
And now it’s on to SMTP and IMAP. We want to spread these connections over our cluster. In the last block we specify the ports for our SMTP and IMAP services. We are creating a frontend and backend for these services. Our ports are 587,143,993. You can adjust the weight value to change the priority between each Exchange Server.
#######################################
# End of Exchange's own protocols,
# STMP and IMAP next
########################################
frontend ft_exchange_smtp
mode tcp
option tcplog
bind IPv4:587 name smtp # VIP
default_backend bk_exchange_smtp
backend bk_exchange_smtp
mode tcp
option tcplog
balance roundrobin
option log-health-checks
server exchange1 IPv4:587 weight 10 check
server exchange2 IPv4:587 weight 20 check
frontend ft_exchange_imaps
mode tcp
option tcplog
bind IPv4:143 name imap
bind IPv4:993 name imaps ssl crt /etc/ssl/cert.pem
default_backend bk_exchange_imaps
backend bk_exchange_imaps
mode tcp
option tcplog
balance leastconn
option log-health-checks
server exchange1 IPv4:993 weight 10 check
server exchange2 IPv4:993 weight 20 check
So that’s it, The entire HAProxy configuration to load balance Exchange 2019 services over two Exchange 2019 Servers.