This article describes NetScaler load balancing configuration for user access to the Exchange 2013 CAS servers.
Citrix ADM StyleBooks simplifies Citrix ADC load balancing configurations for Exchange. Refer to Citrix Docs to learn more - Microsoft Exchange StyleBook.
When we talk about load balancing Exchange CAS, it is mostly about load-balancing HTTPS traffic. While the other types of traffic (SIP, SMTP, IMAP4 and so on) are also important, they are not nearly as big in terms of volume and not nearly as complex. That is why most of this article is about load balancing HTTPS traffic.
In our design, we followed both Microsoft and Citrix recommendations. Microsoft has a good but rather theoretical article (Load Balancing in Exchange 2013) on the Exchange 2013 CAS load balancing. Accumulating our experience of working with both NetScaler and Exchange, we decided on the following:
Configuring Exchange CAS server correctly is a vast task. However, we are only interested in the parts connected to load balancing. In Exchange 2013, there are no CAS arrays anymore, so no need to create one. The only thing to do is to configure TCP/IP idle timeout. The default value is two hours. Set it to 20 minutes. This is done through registry. By default, this parameter in the registry does not exist so we need to add it:
Name: KeepAliveTime
Path: HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
Data Type: REG_DWORD
Value: 0x124F80 (1,200,000 milliseconds)
Below is the load-balancing architecture as seen by the Microsoft:
The basic idea is that Layer 7 proxy allows us to have independent logical entry point for each Exchange web app which in turn allows us to independently switch them on and off based on their individual health rather than overall health of the server. Now, let us see how this general architecture can be translated into NetScaler configuration.
First thing that comes to mind is that some web apps can be grouped together to avoid excessive complexity. We grouped together OWA and ECP. Also, our testing indicates that Outlook Anywhere (RPC) and EWS need to be grouped together in order to avoid transient Outlook errors. In addition, we are not implementing MAPI at this point. It can be easily added later. Finally, we need a catchall default entity for cases when URL does not match anything. The general diagram is presented in Figure 2.
As you can see, user connects to the Content Switch first. Content Switch directs user’s request to the appropriate LB Virtual Server based on the URL. Finally, there is a Service Group bound to each Virtual Server. It is important to note, that, since all the Exchange web apps live on the same server and the same TCP port, all five Virtual Servers and all five Service Groups are nearly identical to each other. They only have different monitors.
Starting with Exchange 2013, we can check individual Exchange app’s health by running a simple HTTP query with the URL https://<server>/<app>/healthcheck.htm. If the app is healthy, the code 200 is returned. NetScaler allows us to easily create Monitors.
Figure 3 and Figure 4 show how to create Monitor for OWA. Make sure to do the following:
To create Monitors for all the other apps, repeat the same with app-appropriate URLs. On the other hand, you can more efficiently, create all the monitors by running the following commands in the NetScaler CLI:
add lb monitor https-ecv-mail-owa HTTP-ECV -send "GET /owa/healthcheck.htm" -recv 200 -LRTM DISABLED -secure YES add lb monitor https-ecv-mail-ecp HTTP-ECV -send "GET /ecp/healthcheck.htm" -recv 200 -LRTM DISABLED -secure YES add lb monitor https-ecv-mail-ews HTTP-ECV -send "GET /EWS/healthcheck.htm" -recv 200 -LRTM DISABLED -secure YES add lb monitor https-ecv-mail-msa HTTP-ECV -send "GET /Microsoft-Server-ActiveSync/healthcheck.htm" -recv 200 -LRTM DISABLED -secure YES add lb monitor https-ecv-mail-oab HTTP-ECV -send "GET /OAB/healthcheck.htm" -recv 200 -LRTM DISABLED -secure YES add lb monitor https-ecv-mail-rpc HTTP-ECV -send "GET /Rpc/healthcheck.htm" -recv 200 -LRTM DISABLED -secure YES add lb monitor https-ecv-mail-mapi HTTP-ECV -send "GET /MAPI/healthcheck.htm" -recv 200 -LRTM DISABLED -secure YES add lb monitor https-ecv-mail-autodisc HTTP-ECV -send "GET /AutoDiscover/healthcheck.htm" -recv 200 -LRTM DISABLED -secure YES
Simply, copy and paste them into the NetScaler CLI.
First, before even creating Service Groups, we need to create Servers. That is easy enough. Just specify a name and an IP address of a CAS server – see Figure 5. You need to create as many of those as many CAS servers you have. We created two - CAS1 and CAS2.
The next step is to create Service Groups in accordance with Figure 2. Again, let us look at OWA as an example. When adding a new Service Group using GUI, make sure you do the following:
Of course, creating all the Service Groups this way might be tedious. Especially, if you have more than one Exchange access point. In addition, as noted above the Service Groups are almost identical (except for Monitors). Makes sense to automate this.
First, run the following to create Service Group objects:
add serviceGroup mail_owa SSL -maxClient 0 -maxReq 0 -cip ENABLED X-Forwarded-For -usip NO -useproxyport YES -cltTimeout 1800 -svrTimeout 1800 -CKA NO -TCPB NO -CMP YES -appflowLog DISABLED add serviceGroup mail_as SSL -maxClient 0 -maxReq 0 -cip ENABLED X-Forwarded-For -usip NO -useproxyport YES -cltTimeout 1800 -svrTimeout 1800 -CKA NO -TCPB NO -CMP YES -appflowLog DISABLED add serviceGroup mail_rpc SSL -maxClient 0 -maxReq 0 -cip ENABLED X-Forwarded-For -usip NO -useproxyport YES -cltTimeout 1800 -svrTimeout 1800 -CKA NO -TCPB NO -CMP YES -appflowLog DISABLED add serviceGroup mail_autodisc SSL -maxClient 0 -maxReq 0 -cip ENABLED X-Forwarded-For -usip NO -useproxyport YES -cltTimeout 1800 -svrTimeout 1800 -CKA NO -TCPB NO -CMP YES -appflowLog DISABLED add serviceGroup mail_oab SSL -maxClient 0 -maxReq 0 -cip ENABLED X-Forwarded-For -usip NO -useproxyport YES -cltTimeout 1800 -svrTimeout 1800 -CKA NO -TCPB NO -CMP YES -appflowLog DISABLED add serviceGroup mail_d SSL -maxClient 0 -maxReq 0 -cip ENABLED X-Forwarded-For -usip NO -useproxyport YES -cltTimeout 1800 -svrTimeout 1800 -CKA NO -TCPB NO -CMP YES -appflowLog DISABLED
Here is the convention used:
Then, run the following to bind all CAS servers to all Service Groups:
bind serviceGroup mail_owa CAS1 443 -CustomServerID "\"None\"" bind serviceGroup mail_owa CAS2 443 -CustomServerID "\"None\"" bind serviceGroup mail_as CAS1 443 -CustomServerID "\"None\"" bind serviceGroup mail_as CAS2 443 -CustomServerID "\"None\"" bind serviceGroup mail_rpc CAS1 443 -CustomServerID "\"None\"" bind serviceGroup mail_rpc CAS2 443 -CustomServerID "\"None\"" bind serviceGroup mail_autodisc CAS1 443 -CustomServerID "\"None\"" bind serviceGroup mail_autodisc CAS2 443 -CustomServerID "\"None\"" bind serviceGroup mail_oab CAS1 443 -CustomServerID "\"None\"" bind serviceGroup mail_oab CAS2 443 -CustomServerID "\"None\"" bind serviceGroup mail_d CAS1 443 -CustomServerID "\"None\"" bind serviceGroup mail_d CAS2 443 -CustomServerID "\"None\""
And finally, bind all the monitors to their respective Service Groups:
bind serviceGroup mail_owa -monitorName https-ecv-mail-owa bind serviceGroup mail_owa -monitorName https-ecv-mail-ecp bind serviceGroup mail_as -monitorName https-ecv-mail-msa bind serviceGroup mail_rpc -monitorName https-ecv-mail-ews bind serviceGroup mail_rpc -monitorName https-ecv-mail-rpc bind serviceGroup mail_oab -monitorName https-ecv-mail-oab bind serviceGroup mail_autodisc -monitorName https-ecv-mail-autodisc bind serviceGroup mail_d -monitorName tcp
Note: We are using a default TCP Monitor for the catch all Service Group.
Additional consideration: by default, all the NetScaler HTTP and SSL Virtual Servers have caching enabled. Our experience indicates that caching causes problems for some Exchange clients. Based on Microsoft's recommendation, we disabled caching by applying "NoCache" policy.
Example: Creating OWA LB Virtual Server Using GUI
When creating OWA LB Virtual Server, male sure you do the following:
First, create the LB Virtual Servers:
add lb vserver mail.citrix.com_443_owa HTTP 0.0.0.0 0 -persistenceType NONE -cltTimeout 1800 add lb vserver mail.citrix.com_443_as HTTP 0.0.0.0 0 -persistenceType NONE -cltTimeout 1800 add lb vserver mail.citrix.com_443_rpc HTTP 0.0.0.0 0 -persistenceType NONE -cltTimeout 1800 add lb vserver mail.citrix.com_443_autodisc HTTP 0.0.0.0 0 -persistenceType NONE -cltTimeout 1800 add lb vserver mail.citrix.com_443_oab HTTP 0.0.0.0 0 -persistenceType NONE -cltTimeout 1800 add lb vserver mail.citrix.com_443_d HTTP 0.0.0.0 0 -persistenceType NONE -cltTimeout 1800
Second, disable caching:
bind lb vserver mail.citrix.com_443_owa -policyName _noCacheRest -priority 100 -gotoPriorityExpression END -type REQUEST bind lb vserver mail.citrix.com_443_as -policyName _noCacheRest -priority 100 -gotoPriorityExpression END -type REQUEST bind lb vserver mail.citrix.com_443_rpc -policyName _noCacheRest -priority 100 -gotoPriorityExpression END -type REQUEST bind lb vserver mail.citrix.com_443_autodisc -policyName _noCacheRest -priority 100 -gotoPriorityExpression END -type REQUEST bind lb vserver mail.citrix.com_443_oab -policyName _noCacheRest -priority 100 -gotoPriorityExpression END -type REQUEST bind lb vserver mail.citrix.com_443_d -policyName _noCacheRest -priority 100 -gotoPriorityExpression END -type REQUEST
Finally, bind the Service Groups to their respective LB Virtual Servers:
bind lb vserver mail.citrix.com_443_owa mail_owa bind lb vserver mail.citrix.com_443_as mail_as bind lb vserver mail.citrix.com_443_rpc mail_rpc bind lb vserver mail.citrix.com_443_autodisc mail_autodisc bind lb vserver mail.citrix.com_443_oab mail_oab bind lb vserver mail.citrix.com_443_d mail_d
Additionally, if you are using XenMobile NetScaler Connector (XNC), you need to bind XNC responder policies to the ActiveSync virtual server:
bind lb vserver mail.citrix.com_443_as -policyName <POLICY_W_DEVICEID> -priority 90 -gotoPriorityExpression END -type REQUEST bind lb vserver mail.citrix.com_443_as -policyName <POLICY_WO_DEVICEID> -priority 100 -gotoPriorityExpression END -type REQUEST
Exchange Content Switch exists for the sole purpose of directing HTTPS traffic to the appropriate LB Virtual Server based on the URL. That behavior is determined by the Content Switch Policies.
Without diving too much into theory, Content Switch is just a logical expression that needs to be bound to the Content Switch and associated with the LB Virtual Server.
Using GUI to create the OWA Content Switch Policy is shown on Figure 14. You can see that the expression is true if the URL starts with either "/owa" or "/ecp". All the policies are shown in Table 1.
Exchange Apps |
Plolicy Name |
Expression |
OWA & ECP |
mail_owa |
HTTP.REQ.URL.SET_TEXT_MODE (IGNORECASE).STARTSWITH("/owa") || HTTP.REQ.URL.SET_TEXT_MODE (IGNORECASE).STARTSWITH("/ecp") |
ActiveSync |
mail_as |
HTTP.REQ.URL.SET_TEXT_MODE (IGNORECASE).STARTSWITH("/Microsoft-Server-ActiveSync") |
Outlook Anywhere & EWS |
mail_rpc |
HTTP.REQ.URL.SET_TEXT_MODE (IGNORECASE).STARTSWITH("/Rpc") || HTTP.REQ.URL.SET_TEXT_MODE (IGNORECASE).STARTSWITH("/EWS") |
Autodiscover |
mail_autodisc |
HTTP.REQ.URL.SET_TEXT_MODE (IGNORECASE).STARTSWITH("/Autodiscover") |
OAB |
mail_oab |
HTTP.REQ.URL.SET_TEXT_MODE (IGNORECASE).STARTSWITH("/OAB") |
To create all the policies, run the following in the CLI:
add cs policy mail_owa -rule "HTTP.REQ.URL.SET_TEXT_MODE (IGNORECASE).STARTSWITH(\"/owa\") || HTTP.REQ.URL.SET_TEXT_MODE (IGNORECASE).STARTSWITH(\"/ecp\")" add cs policy mail_as -rule "HTTP.REQ.URL.SET_TEXT_MODE (IGNORECASE).STARTSWITH(\"/Microsoft-Server-ActiveSync\")" add cs policy mail_rpc -rule "HTTP.REQ.URL.SET_TEXT_MODE (IGNORECASE).STARTSWITH(\"/Rpc\") || HTTP.REQ.URL.SET_TEXT_MODE (IGNORECASE).STARTSWITH(\"/EWS\")" add cs policy mail_autodisc -rule "HTTP.REQ.URL.SET_TEXT_MODE (IGNORECASE).STARTSWITH(\"/Autodiscover\")" add cs policy mail_oab -rule "HTTP.REQ.URL.SET_TEXT_MODE (IGNORECASE).STARTSWITH(\"/OAB\")"
Lastly, we need to create the content switch and bind all the policies. Do the following:
In order to automate creating the Content Switch, run the following in the CLI instead:
add cs vserver mail.citrix.com_cs_443 SSL <ip_address> 443 -cltTimeout 1800 bind ssl vserver mail.citrix.com_cs_443 -certkeyName <cert_name>
You need to enter specific IP address and certificate name.
At this point, the Content Switch is created but it is "empty". Now you need to bind the Content Switch Policies and associate them with LB Virtual Servers.
To bind the policies, open the Content Switch properties and click on CSV - Figure 17. To bind each policy, you need to a) click Insert Policy; b) select the policy name from the dropdown list; and c) select LB Virtual Server name from the Target dropdown list. The last policy you bind should be "(Default)". That is not really a policy. You are just binding the catchall LB Virtual server.
Figure 17 is a good example of what it should look like after you are done.
To perform the same operations in CLI, run the following:
bind cs vserver mail.citrix.com_cs_443 -policyName mail_as -targetLBVserver mail.citrix.com_443_as -priority 80 bind cs vserver mail.citrix.com_cs_443 -policyName mail_rpc -targetLBVserver mail.citrix.com_443_rpc -priority 90 bind cs vserver mail.citrix.com_cs_443 -policyName mail_owa -targetLBVserver mail.citrix.com_443_owa -priority 100 bind cs vserver mail.citrix.com_cs_443 -policyName mail_oab -targetLBVserver mail.citrix.com_443_oab -priority 105 bind cs vserver mail.citrix.com_cs_443 -policyName mail_autodisc -targetLBVserver mail.citrix.com_443_autodisc -priority 110 bind cs vserver mail.citrix.com_cs_443 -lbvserver mail.citrix.com_443_d
Load balancing other types of traffic is simple: we create TCP LB Virtual Server for the following ports:
Other things to pay attention: