Microsoft ExchangeWindows

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.

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button