Citrix Netscaler – Loadbalancing Exchange 2013/2016 (Walkthrough Guide)

If you get the task to load balance Exchange with NetScaler you will find a lot of whitepapers from Citrix with missing information and false configuration recommendations. I was bumping my head against the wall until I got a running configuration with all desired features. Here is the complete walkthrough guide to setup your Exchange environment with a single public ip address. Additional features like AAA, Front End Optimization  and Integrated Caching will depend on your current NetScaler licence.

Table of contents
1. Feature Matrix
2. Network Topology
3. Requirements
3.1 Firewall Rules
4. Configuration
4.1 Features
4.2 Server
4.3 Monitors
4.4 Service Groups
4.5 Load Balancer
4.6 Content Switch
4.7 AAA (Enterprise)
4.7.1 Authentication Policies
4.7.2 SSO Traffic Policies
4.8 Front End Optimization (Enterprise)
4.9 Integrated Caching (Platinum)

1. Feature Matrix

Licence

Load Balancing

Content Switching

Responder

AAA

Front End Optimization

Integrated Caching

Standard

x

x

x

Enterprise

x

x

x

x

x

Platinum

x

x

x

x

x

x

2. Network Topology

diagram

3. Requirements

  • One public ip address
  • Two private IP addresses (Content Switch and Load Balancer)
  • Working DNS/NTP on NetScaler
  • Wildcard SSL certificate

3.1 Firewall Rules

From

To

Port

Description

SNIP

DNS Server

UDP/TCP 53

DNS

SNIP

NTP Server

UDP 123

NTP

SNIP

Domain Controller

TCP 389

LDAP

SNIP

Domain Controller

TCP 636

LDAPS

NSIP

Exchange Server

TCP 25, 465, 587

SMTP Monitor

SNIP

Exchange Server

TCP 25, 465, 587

SMTP

SNIP

Exchange Server

TCP 143, 993

IMAP

SNIP

Exchange Server

HTTPS – 443

OWA, AutoDiscover, ActiveSync, MAPI, etc.

Internet

SMTP LB IP

TCP 25, 465, 587

SMTP

Internet

IMAP LB IP

TCP 143, 993

IMAP

Internet

Content Switch VIP

HTTP – 80

Web Traffic

Internet

Content Switch VIP

HTTPS – 443

Web Traffic

If you dont load balance DNS/LDAPS/NTP the traffic will flow from the NSIP. In my setup the servers are load balanced –> The SNIP is communicating with the backend servers.

4. Configuration

4.1 Features

#Features
enable ns feature CS,RESPONDER,LB,SSL

4.2 Server

#Create serves
#Replace FQDN and ip address regarding  your environment
add server EX01.lab.local 192.168.2.102
add server EX02.lab.local 192.168.2.103

4.3 Monitors

Name

Type

Standard Parameter

Send String

mon_smtp

SMTP

mon_owa

HTTP-ECV

Secure

“GET /owa/healthcheck.htm”

mon_activesync

HTTP-ECV

Secure

“GET /Microsoft-Server-ActiveSync/healthcheck.htm”

mon_rpc

HTTP-ECV

Secure

“GET /rpc/healthcheck.htm”

mon_ews

HTTP-ECV

Secure

“GET /ews/healthcheck.htm”

mon_autodiscover

HTTP-ECV

Secure

“GET /Autodiscover/healthcheck.htm”

mon_mapi

HTTP-ECV

Secure

“GET /mapi/healthcheck.htm”

mon_ecp

HTTP-ECV

Secure

“GET /ecp/healthcheck.htm”

#Create monitors
add lb monitor mon_smtp SMTP
add lb monitor mon_owa HTTP-ECV -send "GET /owa/healthcheck.htm" recv 200 -LRTM DISABLED -secure YES
add lb monitor mon_activesync HTTP-ECV -send "GET /Microsoft-Server-ActiveSync/healthcheck.htm" recv 200 -LRTM DISABLED -secure YES
add lb monitor mon_rpc HTTP-ECV -send "GET /rpc/healthcheck.htm" recv 200 -LRTM DISABLED -secure YES
add lb monitor mon_ews HTTP-ECV -send "GET /ews/healthcheck.htm" recv 200 -LRTM DISABLED -secure YES
add lb monitor mon_autodiscover HTTP-ECV -send "GET /Autodiscover/healthcheck.htm" recv 200 -LRTM DISABLED -secure YES
add lb monitor mon_oab HTTP-ECV -send "GET /oab/healthcheck.htm" recv 200 -LRTM DISABLED -secure YES
add lb monitor mon_mapi HTTP-ECV -send "GET /mapi/healthcheck.htm" recv 200 -LRTM DISABLED -secure YES
add lb monitor mon_ecp HTTP-ECV -send "GET /ecp/healthcheck.htm" recv 200 -LRTM DISABLED -secure YES

4.4 Service Groups

Name

Protocol

Monitor

svcgrp_ex2016_smtp_25

TCP

mon_smtp

svcgrp_ex2016_smtp_465

TCP

mon_smtp

svcgrp_ex2016_smtp_587

TCP

mon_smtp

svcgrp_ex2016_imap_143

TCP

TCP

svcgrp_ex2016_imap_993

TCP

TCP

svcgrp_ex2016_owa

SSL

mon_owa

svcgrp_ex2016_activesync

SSL

mon_activesync

svcgrp_ex2016_rpc

SSL

mon_rpc

svcgrp_ex2016_ews

SSL

mon_ews

svcgrp_ex2016_autodisover

SSL

mon_autodiscover

svcgrp_ex2016_oab

SSL

mon_oab

svcgrp_ex2016_mapi

SSL

mon_mapi

svcgrp_ex2016_epc

SSL

mon_epc

#Create Service Groups
add serviceGroup svcgrp_ex2016_smtp_25 TCP
add serviceGroup svcgrp_ex2016_smtp_465 TCP
add serviceGroup svcgrp_ex2016_smtp_587 TCP
add serviceGroup svcgrp_ex2016_imap_143 TCP
add serviceGroup svcgrp_ex2016_imap_993 TCP
add serviceGroup svcgrp_ex2016_owa SSL
add serviceGroup svcgrp_ex2016_activesync SSL
add serviceGroup svcgrp_ex2016_rpc SSL
add serviceGroup svcgrp_ex2016_ews SSL
add serviceGroup svcgrp_ex2016_autodisover SSL
add serviceGroup svcgrp_ex2016_oab SSL
add serviceGroup svcgrp_ex2016_mapi SSL
add serviceGroup svcgrp_ex2016_ecp SSL
#Bind Service Groups
#Replace FQDN and ip address regarding your environment
bind servicegroup svcgrp_ex2016_smtp_25 EX01.lab.local 25
bind servicegroup svcgrp_ex2016_smtp_25 EX02.lab.local 25
bind serviceGroup svcgrp_ex2016_smtp_25 -monitorName mon_smtp

bind servicegroup svcgrp_ex2016_smtp_465 EX01.lab.local 465
bind servicegroup svcgrp_ex2016_smtp_465  EX02.lab.local 465
bind serviceGroup svcgrp_ex2016_smtp_465 -monitorName mon_smtp

bind servicegroup svcgrp_ex2016_smtp_587 EX01.lab.local 587
bind servicegroup svcgrp_ex2016_smtp_587 EX02.lab.local 587
bind serviceGroup svcgrp_ex2016_smtp_587 -monitorName mon_smtp

bind servicegroup svcgrp_ex2016_imap_143 EX01.lab.local 143
bind servicegroup svcgrp_ex2016_imap_143 EX02.lab.local 143
bind serviceGroup svcgrp_ex2016_imap_143 -monitorName TCP

bind servicegroup svcgrp_ex2016_imap_993 EX01.lab.local 993
bind servicegroup svcgrp_ex2016_imap_993 EX02.lab.local 993
bind serviceGroup svcgrp_ex2016_imap_993 -monitorName TCP

bind servicegroup svcgrp_ex2016_owa EX01.lab.local 443
bind servicegroup svcgrp_ex2016_owa EX02.lab.local 443
bind serviceGroup svcgrp_ex2016_owa -monitorName mon_owa

bind servicegroup svcgrp_ex2016_activesync EX01.lab.local 443
bind servicegroup svcgrp_ex2016_activesync EX02.lab.local 443
bind servicegroup svcgrp_ex2016_activesync -monitorName mon_activesync

bind servicegroup svcgrp_ex2016_rpc EX01.lab.local 443
bind servicegroup svcgrp_ex2016_rpc EX02.lab.local 443
bind servicegroup svcgrp_ex2016_rpc -monitorName mon_rpc

bind servicegroup svcgrp_ex2016_ews EX01.lab.local 443
bind servicegroup svcgrp_ex2016_ews EX02.lab.local 443
bind servicegroup svcgrp_ex2016_ews -monitorName mon_ews

bind servicegroup svcgrp_ex2016_autodisover EX01.lab.local 443
bind servicegroup svcgrp_ex2016_autodisover EX02.lab.local 443
bind servicegroup svcgrp_ex2016_autodisover -monitorName mon_autodiscover

bind servicegroup svcgrp_ex2016_oab EX01.lab.local 443
bind servicegroup svcgrp_ex2016_oab EX02.lab.local 443
bind servicegroup svcgrp_ex2016_oab -monitorName mon_oab

bind servicegroup svcgrp_ex2016_mapi EX01.lab.local 443
bind servicegroup svcgrp_ex2016_mapi EX02.lab.local 443
bind servicegroup svcgrp_ex2016_mapi -monitorName mon_mapi

bind servicegroup svcgrp_ex2016_ecp EX01.lab.local 443
bind servicegroup svcgrp_ex2016_ecp EX02.lab.local 443
bind servicegroup svcgrp_ex2016_ecp -monitorName mon_ecp

4.5 Load Balancer

vServer

IP address

Method

Persistence

Timeout

Protocol

Authentication (AAA)

SMTP

192.168.2.248

Least Connection

NONE

Default

TCP

IMAP

192.168.2.248

Least Connection

NONE

Default

TCP

OWA

0.0.0.0

Least Connection

NONE

Default

SSL

FBA

ECP

0.0.0.0

Least Connection

NONE

Default

SSL

FBA

ActiveSync

0.0.0.0

SRCIPDESTIP

NONE

Default

SSL

401 Based

AutoDiscover

0.0.0.0

SourceIP

NONE

30

SSL

401 Based

RPC

0.0.0.0

Least Connection

RULE – HTTP.REQ.HEADER(“Authorization”)

240

SSL

EWS

0.0.0.0

Least Connection

NONE

Default

SSL

OAB

0.0.0.0

Least Connection

NONE

Default

SSL

MAPI

0.0.0.0

Least Connection

RULE – HTTP.REQ.HEADER(“Authorization”)

240

SSL

#Create Load Balancer
add lb vserver lb_vsrv_ex2016_smtp_25 TCP 192.168.2.248 25
add lb vserver lb_vsrv_ex2016_smtp_465 TCP 192.168.2.248 465
add lb vserver lb_vsrv_ex2016_smtp_587 TCP 192.168.2.248 587
add lb vserver lb_vsrv_ex2016_imap_143 TCP 192.168.2.248 143
add lb vserver lb_vsrv_ex2016_imap_993 TCP 192.168.2.248 993
add lb vserver lb_vsrv_ex2016_owa SSL 0.0.0.0 0 -persistenceType NONE
add lb vserver lb_vsrv_ex2016_activesync SSL 0.0.0.0 0 -persistenceType SRCIPDESTIP
add lb vserver lb_vsrv_ex2016_rpc SSL 0.0.0.0 0 -persistenceType RULE -rule 'HTTP.REQ.HEADER("Authorization")' -timeout 240
add lb vserver lb_vsrv_ex2016_ews SSL 0.0.0.0 0 -persistenceType NONE
add lb vserver lb_vsrv_ex2016_autodiscover SSL 0.0.0.0 0 -persistenceType SOURCEIP -timeout 30
add lb vserver lb_vsrv_ex2016_oab SSL 0.0.0.0 0 -persistenceType NONE
add lb vserver lb_vsrv_ex2016_mapi SSL 0.0.0.0 0 -persistenceType RULE -rule 'HTTP.REQ.HEADER("Authorization")' -timeout 240
add lb vserver lb_vsrv_ex2016_ecp SSL 0.0.0.0 0 -persistenceType NONE
#Bind Service Groups to vServer
bind lb vserver lb_vsrv_ex2016_smtp_25 svcgrp_ex2016_smtp_25
bind lb vserver lb_vsrv_ex2016_smtp_465 svcgrp_ex2016_smtp_465
bind lb vserver lb_vsrv_ex2016_smtp_587 svcgrp_ex2016_smtp_587
bind lb vserver lb_vsrv_ex2016_imap_143 svcgrp_ex2016_imap_143
bind lb vserver lb_vsrv_ex2016_imap_993 svcgrp_ex2016_imap_993
bind lb vserver lb_vsrv_ex2016_owa svcgrp_ex2016_owa
bind lb vserver lb_vsrv_ex2016_activesync svcgrp_ex2016_activesync
bind lb vserver lb_vsrv_ex2016_rpc svcgrp_ex2016_rpc
bind lb vserver lb_vsrv_ex2016_ews svcgrp_ex2016_ews
bind lb vserver lb_vsrv_ex2016_autodiscover svcgrp_ex2016_autodisover
bind lb vserver lb_vsrv_ex2016_oab svcgrp_ex2016_oab
bind lb vserver lb_vsrv_ex2016_mapi svcgrp_ex2016_mapi
bind lb vserver lb_vsrv_ex2016_ecp svcgrp_ex2016_ecp
#Bind SSL certificate
#Replace certificate name
bind ssl vserver lb_vsrv_ex2016_owa -certkeyName 'Wildcard-Flashmob'
bind ssl vserver lb_vsrv_ex2016_activesync -certkeyName 'Wildcard-Flashmob'
bind ssl vserver lb_vsrv_ex2016_rpc -certkeyName 'Wildcard-Flashmob'
bind ssl vserver lb_vsrv_ex2016_ews -certkeyName 'Wildcard-Flashmob'
bind ssl vserver lb_vsrv_ex2016_autodiscover -certkeyName 'Wildcard-Flashmob'
bind ssl vserver lb_vsrv_ex2016_oab -certkeyName 'Wildcard-Flashmob'
bind ssl vserver lb_vsrv_ex2016_mapi -certkeyName 'Wildcard-Flashmob'
bind ssl vserver lb_vsrv_ex2016_ecp -certkeyName 'Wildcard-Flashmob'

4.6 Content Switch

Name

Action

Target

Expression

cs_pol_owa

cs_act_owa

lb_vsrv_ex2016_owa

HTTP.REQ.URL.SET_TEXT_MODE(IGNORECASE).CONTAINS(“/owa”)

cs_pol_ews

cs_act_ews

lb_vsrv_ex2016_ews

HTTP.REQ.URL.SET_TEXT_MODE(IGNORECASE).CONTAINS(“/ews”)

cs_pol_activesync

cs_act_activesync

lb_vsrv_ex2016_activesync

HTTP.REQ.URL.SET_TEXT_MODE(IGNORECASE).CONTAINS(“Microsoft”)

cs_pol_autodiscover

cs_act_autodiscover

lb_vsrv_ex2016_autodiscover

HTTP.REQ.URL.SET_TEXT_MODE(IGNORECASE).CONTAINS(“/autodiscover”)

cs_pol_rpc

cs_act_rpc

lb_vsrv_ex2016_rpc

HTTP.REQ.URL.SET_TEXT_MODE(IGNORECASE).CONTAINS(“/rpc”)

cs_pol_ews

cs_act_ews

lb_vsrv_ex2016_ews

HTTP.REQ.URL.SET_TEXT_MODE(IGNORECASE).CONTAINS(“/ews”)

cs_pol_oab

cs_act_oab

lb_vsrv_ex2016_oab

HTTP.REQ.URL.SET_TEXT_MODE(IGNORECASE).CONTAINS(“/oab”)

cs_pol_mapi

cs_act_mapi

lb_vsrv_ex2016_mapi

HTTP.REQ.URL.SET_TEXT_MODE(IGNORECASE).CONTAINS(“/mapi”)

cs_pol_cgi

cs_act_owa

lb_vsrv_ex2016_owa

HTTP.REQ.URL.SET_TEXT_MODE(IGNORECASE).CONTAINS(“/cgi”)

cs_pol_owa_redirect

cs_act_owa

lb_vsrv_ex2016_owa

HTTP.REQ.HOSTNAME.EQ(“mail.flashmob-saulgau.de”)

#Create Content Switch
#Replace IP address of Content Switch
add cs vserver cs_exchange2016_http HTTP 192.168.1.20 80
add cs vserver cs_exchange2016_ssl SSL 192.168.1.20 443
#Replace certificate name
bind ssl vserver cs_exchange2016_ssl -certkeyName 'Wildcard-Flashmob'
#Create Content Switch Policies
add cs action cs_act_owa -targetLBVserver lb_vsrv_ex2016_owa
add cs policy cs_pol_owa -rule 'HTTP.REQ.URL.SET_TEXT_MODE(IGNORECASE).CONTAINS("/owa")' -action cs_act_owa
add cs action cs_act_ews -targetLBVserver  lb_vsrv_ex2016_ews
add cs policy cs_pol_ews -rule 'HTTP.REQ.URL.SET_TEXT_MODE(IGNORECASE).CONTAINS("/ews")' -action cs_act_ews
add cs action cs_act_autodiscover -targetLBVserver  lb_vsrv_ex2016_autodiscover
add cs policy cs_pol_autodiscover -rule 'HTTP.REQ.URL.SET_TEXT_MODE(IGNORECASE).CONTAINS("/autodiscover")' -action cs_act_autodiscover
add cs action cs_act_activesync -targetLBVserver  lb_vsrv_ex2016_activesync
add cs policy cs_pol_activesync -rule 'HTTP.REQ.URL.SET_TEXT_MODE(IGNORECASE).CONTAINS("Microsoft")' -action cs_act_activesync
add cs action cs_act_oab -targetLBVserver  lb_vsrv_ex2016_oab
add cs policy cs_pol_oab -rule 'HTTP.REQ.URL.SET_TEXT_MODE(IGNORECASE).CONTAINS("/oab")' -action cs_act_oab
add cs action cs_act_mapi -targetLBVserver  lb_vsrv_ex2016_mapi
add cs policy cs_pol_mapi -rule 'HTTP.REQ.URL.SET_TEXT_MODE(IGNORECASE).CONTAINS("/mapi")' -action cs_act_mapi
add cs action cs_act_rpc -targetLBVserver  lb_vsrv_ex2016_rpc
add cs policy cs_pol_rpc -rule 'HTTP.REQ.URL.SET_TEXT_MODE(IGNORECASE).CONTAINS("/rpc")' -action cs_act_rpc
add cs action cs_act_ecp -targetLBVserver  lb_vsrv_ex2016_ecp
add cs policy cs_pol_ecp -rule 'HTTP.REQ.URL.SET_TEXT_MODE(IGNORECASE).CONTAINS("/ecp")' -action cs_act_ecp
#OWA Fix https://support.citrix.com/article/CTX209060
add cs policy cs_pol_cgi -rule 'HTTP.REQ.URL.SET_TEXT_MODE(IGNORECASE).CONTAINS("/cgi")' -action cs_act_owa
#Redirect to OWA if only https://mail.flashmob-saulgau.de will be entered
#Replace the mail FQDN
add cs policy cs_pol_owa_redirect -rule 'HTTP.REQ.HOSTNAME.EQ("mail.flashmob-saulgau.de")' -action cs_act_owa
#Bind Content Switch Policies
bind cs vserver cs_exchange2016_ssl -policyName cs_pol_owa -priority 100
bind cs vserver cs_exchange2016_ssl -policyName cs_pol_ews -priority 110
bind cs vserver cs_exchange2016_ssl -policyName cs_pol_autodiscover -priority 120
bind cs vserver cs_exchange2016_ssl -policyName cs_pol_activesync -priority 130
bind cs vserver cs_exchange2016_ssl -policyName cs_pol_oab -priority 140
bind cs vserver cs_exchange2016_ssl -policyName cs_pol_mapi -priority 150
bind cs vserver cs_exchange2016_ssl -policyName cs_pol_rpc -priority 160
bind cs vserver cs_exchange2016_ssl -policyName cs_pol_ecp -priority 170
bind cs vserver cs_exchange2016_ssl -policyName cs_pol_cgi -priority 180
bind cs vserver cs_exchange2016_ssl -policyName cs_pol_owa_redirect -priority 190
#OWA HTTP Redirect (Responder)
#Replace the mail FQDN
add responder action resp_act_owa redirect '"https://"+HTTP.REQ.HOSTNAME+"/owa/"'
add responder policy resp_pol_owa 'HTTP.REQ.HOSTNAME.CONTAINS("mail.flashmob-saulgau.de")' resp_act_owa
bind cs vserver cs_exchange2016_http -policyName resp_pol_owa -priority 100

4.7 AAA (Enterprise)

If you have an enterprise licence you can let take the authenication on the AAA server and redirect the credentials to OWA. This feature offers improved security integration and n-factor authentication like RADIUS, SAML and certificate authentication is possible. If you enter the mail domain you will be redirected to the AAA login page.

aaa

If you want to you use “401 Based Authentication” on the Autodiscover service you need to set the following registry key in the user profile.

HKCU\SOFTWARE\Microsoft\Office\16.0\Common\Identity\EnableADAL (REG_DWORD 0)

Otherwise Outlook 2016 is crashing while setting up the profile (ADAL is enabled by default)
NetScaler is not supporting ADAL at the moment.
https://discussions.citrix.com/topic/376086-outlook-2016-and-autodiscover/

#Enable AAA Feature
enable ns feature AAA
#Create AAA Server
add authentication vserver AAA_Exchange_2016 SSL 0.0.0.0
#Replace certificate name
bind ssl vserver AAA_Exchange_2016 -certkeyName 'Wildcard-Flashmob'
bind authentication vserver AAA_Exchange_2016 -portaltheme X1
#Replace AAA FQDN
set authentication vserver AAA_Exchange_2016 -authenticationDomain 'flashmob-saulgau.de'

4.7.1 Authentication Policies

In this setup we  will authenticate with LDAP only. For this we need create two policies.

1.) LDAP with sAMAccountName
2.) LDAP with userPrincipalName

The user can login with “test” or “test@lab.local”.

#LDAP SAM + UPN Policy
#Replace server ip, ldapbase, bind user and password
add authentication ldapaction LDAP_UPN -serverip 192.168.2.1 -secType SSL -serverPort 636 -ldapBase "DC=lab,DC=local" -ldapBindDn ns-ldap@lab.local -ldapBindDnPassword ##password## -ldapLoginName userPrincipalName -groupAttrName "memberOf" -subAttributeName "cn" -ssoNameAttribute userPrincipalName -passwdChange ENABLED -followReferrals ON
add authentication ldapaction LDAP_SAM -serverip 192.168.2.1 -secType SSL -serverPort 636 -ldapBase "DC=lab,DC=local" -ldapBindDn ns-ldap@lab.local -ldapBindDnPassword ##password## -ldapLoginName sAMAccountName -groupAttrName "memberOf" -subAttributeName "cn" -ssoNameAttribute userPrincipalName -passwdChange ENABLED -followReferrals ON
add authentication ldappolicy LDAP_UPN ns_true LDAP_UPN
add authentication ldappolicy LDAP_SAM ns_true LDAP_SAM
#Bind LDAP Policies
bind authentication vserver AAA_Exchange_2016 -policy LDAP_UPN -priority 100
bind authentication vserver AAA_Exchange_2016 -policy LDAP_SAM -priority 110

4.7.2 SSO Traffic Policies

#Create AAA Session Policy
#Replace "ssoDomain"
add tm sessionAction tm_act_exchange2016_owa_sso -defaultAuthorization ALLOW -SSO ON -ssoDomain 'lab.local'
add tm sessionPolicy tm_pol_exchange2016_owa_sso 'HTTP.REQ.URL.CONTAINS("/owa/auth/logon.aspx")' tm_act_exchange2016_owa_sso
#Create SSO Form and Policies
add tm formSSOAction sso_profile_exchange_2016_owa -actionURL "/owa/auth.owa" -userField "username" -passwdField "password" -responsesize "60000" -ssoSuccessRule 'HTTP.RES.SET_COOKIE.COOKIE("cadata").VALUE("cadata").LENGTH.GT(70)' -nvtype DYNAMIC -submitMethod POST

add tm trafficAction traffic_prof_exchange_2016_owa -SSO ON -appTimeout 1 -formSSOAction sso_profile_exchange_2016_owa
add tm trafficAction traffic_prof_exchange_2016_owa_logout -InitiateLogout ON

add tm trafficPolicy traffic_pol_exchange_2016_owa 'HTTP.REQ.URL.CONTAINS("/owa/auth/logon.aspx")' traffic_prof_exchange_2016_owa
add tm trafficPolicy traffic_pol_exchange_2016_owa_logout 'HTTP.REQ.URL.CONTAINS("/owa/logoff.owa")' traffic_prof_exchange_2016_owa_logout
#Bind SSO Policies to the OWA vServer
bind lb vserver lb_vsrv_ex2016_owa -policyName traffic_pol_exchange_2016_owa -priority 100 -gotoPriorityExpression END -type REQUEST
bind lb vserver lb_vsrv_ex2016_owa -policyName traffic_pol_exchange_2016_owa_logout -priority 110 -gotoPriorityExpression END -type REQUEST
#Set 401 and FBA authentication
#Replace AuthenticationHost FQDN
set lb vserver lb_vsrv_ex2016_owa -Authentication ON -authnVsName AAA_Exchange_2016 -AuthenticationHost aaa.flashmob-saulgau.de
set lb vserver lb_vsrv_ex2016_ecp -Authentication ON -authnVsName AAA_Exchange_2016 -AuthenticationHost aaa.flashmob-saulgau.de
set lb vserver lb_vsrv_ex2016_activesync -authn401 ON -authnVsName AAA_Exchange_2016 -AuthenticationHost aaa.flashmob-saulgau.de
set lb vserver lb_vsrv_ex2016_autodiscover -authn401 ON -authnVsName AAA_Exchange_2016 -AuthenticationHost aaa.flashmob-saulgau.de
#Content Switch AAA
#Replace AuthenticationHost FQDN
add cs action cs_act_aaa -targetVserver AAA_Exchange_2016
add cs policy cs_pol_aaa -rule 'HTTP.REQ.HOSTNAME.EQ("aaa.flashmob-saulgau.de")' -action cs_act_aaa
bind cs vserver cs_exchange2016_ssl -policyName cs_pol_aaa -priority 90

The priorty of the AAA content switch policy must be the one with the lowest priority.

4.8 Front End Optimization (Enterprise)

I couldnt test this feature too much so I configured like descriped in the Citrix whitepaper. If the optimization action “Moderate” is not suiting your expectations you can try the “Aggresive” mode. You can verify if FOE is working within the GUI. Go to Optimization –> Front End Optimization –> Statics (“stat feo” in CLI)

foe1

foe2

#Enable Front End Optimization
enable ns feature FEO
#Front End Optimization
#Replace FQDN
add feo policy feo_pol_exchange2016 'HTTP.REQ.HOSTNAME.CONTAINS("mail.flashmob-saulgau.de")' MODERATE
bind cs vserver cs_exchange2016_ssl -policyName feo_pol_exchange2016 -priority 100

4.9 Integrated Caching (Platinum)

In the Citrix docs its recommended to allocate less than half of the NetScalers memory for integrated caching. Set the parameter “memLimit” fitting to your appliance. I’m using 500MB. You can verify if the cache is working within the GUI. Go to Optimization –> Integrated Caching –> View Cache Objects (“show cache object” in CLI)

cache1

cache2

#Enable Integrated Caching
enable ns feature IC
#Integrated Caching
set cache parameter -memLimit 500
set serviceGroup svcgrp_ex2016_owa -CMP YES
set serviceGroup svcgrp_ex2016_activesync -CMP YES
set serviceGroup svcgrp_ex2016_rpc -CMP YES
set serviceGroup svcgrp_ex2016_ews -CMP YES
set serviceGroup svcgrp_ex2016_autodisover -CMP YES
set serviceGroup svcgrp_ex2016_oab -CMP YES
set serviceGroup svcgrp_ex2016_mapi -CMP YES
set serviceGroup svcgrp_ex2016_ecp -CMP YES

add cache contentGroup cache_group_exchange2016 -type HTTP -weakNegRelExpiry 233 -weakPosRelExpiry 233
add cache policy cache_pol_exchange2016 -rule 'TRUE' -action CACHE -storeInGroup cache_group_exchange2016

bind cs vserver cs_exchange2016_ssl -policyName cache_pol_exchange2016 -priority 100 -type REQUEST

I hope this guide helped you to load balance Exchange with Citrix NetScaler.
If you find any misconfigurations or have improvments please contact me.

28 thoughts on “Citrix Netscaler – Loadbalancing Exchange 2013/2016 (Walkthrough Guide)

Add yours

  1. hi julian, awesome blog thank you for that, and i love to have directly the netscaler commands not the GUI. i did create after 2 days same netscaler config, but for me in all of this guides, it is not normal to make also the loadbalancing steps also for the SMTP and IMAP Traffic? I mean, what is the BestPractice here? Only Loadbalance SMTP Port25 or also Port 587, 143 and so on? Or did that make Exchange 2016 with other Tools? regards frank

    Like

  2. hi julian, i have make this, only on the monitors i am not sure, if there is maybe a better monitor as http-evc

    # Create and Bind LB Server for SMTP Traffic / only for SMTP Traffic / when you want / must be configured with Exchange Admin / Relay Rules than on Netscaler
    # Create and Bind LB Server for SMTP Traffic Port 25 and Port 465 and Port 587 and also IMAP Port 143
    add serviceGroup lb_svg_exch2016_smtp TCP
    add lb vserver lb_exch2016_vsrv_smtp TCP 192.168.0.11 25
    bind lb vserver lb_exch2016_vsrv_smtp lb_svg_exch2016_smtp
    bind serviceGroup lb_svg_exch2016_smtp exchange01.your.domain 25
    bind serviceGroup lb_svg_exch2016_smtp exchange02.your.domain 25
    bind serviceGroup lb_svg_exch2016_smtp -monitorName tcp
    add serviceGroup lb_svg_exch2016_smtp_587 TCP
    add lb vserver lb_exch2016_vsrv_smtp_587 TCP 192.168.0.11 587
    bind lb vserver lb_exch2016_vsrv_smtp_587 lb_svg_exch2016_smtp_587
    bind serviceGroup lb_svg_exch2016_smtp_587 exchange01.your.domain 587
    bind serviceGroup lb_svg_exch2016_smtp_587 exchange02.your.domain 587
    bind serviceGroup lb_svg_exch2016_smtp_587 -monitorName tcp
    add serviceGroup lb_svg_exch2016_imap TCP
    add lb vserver lb_exch2016_vsrv_imap TCP 192.168.0.11 143
    bind lb vserver lb_exch2016_vsrv_imap lb_svg_exch2016_imap
    bind serviceGroup lb_svg_exch2016_imap exchange01.your.domain 143
    bind serviceGroup lb_svg_exch2016_imap exchange02.your.domain 143
    bind serviceGroup lb_svg_exch2016_imap -monitorName tcp
    add serviceGroup lb_svg_exch2016_smtp_465 TCP
    add lb vserver lb_exch2016_vsrv_smtp_465 TCP 192.168.0.11 465
    bind lb vserver lb_exch2016_vsrv_smtp_465 lb_svg_exch2016_smtp_465
    bind serviceGroup lb_svg_exch2016_smtp_465 exchange01.your.domain 465
    bind serviceGroup lb_svg_exch2016_smtp_465 exchange02.your.domain 465
    bind serviceGroup lb_svg_exch2016_smtp_465 -monitorName tcp

    maybe you make it same or better
    regards frank

    Liked by 1 person

  3. Nice post. Quick question.

    If I create a LB VIP on the NetScaler with port/protocol of */ANY to the back-end CAS servers, All of the services work fine, OWA, Active Sync, OAB, RPC, etc, all function..

    BY following the guide it breaks my outlook clients (externally) they prompt for password continuously and users cannot login.

    Any ideas?

    Like

  4. How do you configure IMAP monitor for Exchange 2013? Netscaler routes traffic to Exchange even if the server is in maintenance mode because it sees that port 993 is available. Based from packet capture, it is receiving acknowledgement from the server when it checks port 993. Once the traffic is routed to Exchange, it fails because the associated IMAP service is in maintenance mode.

    Like

  5. Hi Julian,

    great blog. Help so much.
    But I have some questions about the general structure of your topology, because I am also quite new to NetScaler.

    1. Where do you need the LB VIP 192.168.2.248? According to the sketch, the internal clients alsoconnect to CS VIP?! And there is no reference to the LB VIP … should it have to be entered internally somewhere?
    2. Where do you use an external IP – mentioned in requirements? I find in your deployment only the internal CS VIP. Where and how should I set up the external address? Another CS for external or how is externel traffic redirected to internal CS VIP?

    Thank you in advance

    Greetings Kevin

    Like

    1. Hi Kevin,
      1.) The LB VIP .248 is only for load balancing IMAP/SMTP traffic. Internal Clients should connect to the internal NetScaler appliance. If you only have a NetScaler in the DMZ you can create an additional vServer without AAA authenication and create a dns record which pointing to the VIP.
      2.) For the external access you need to create a DNAT to your NetScaler CS VIP. Internal access is going directly to the Content Switch.
      Greets
      Julian

      Like

      1. Hey Julian,
        Thank you very much. Your explanation helped me a lot. Then I have only one more question.
        If I was slipping internal Clients, as well as external Clients via a NetScaler in the DMZ, would I create another LB vServer for each Exchange LB (SMTP, IMAP, OWA, EWS, …) without attached AAA? And would I need a second CS vServer (internal use) without AAA?
        If so, is this a possible setup?:
        > external IP via INAT to CS VIP (with AAA for external)
        – > LB VIP for SMTP and IMAP (with AAA for external)
        – > LBs 0.0.0.0 for OWA, autodiscover, … (with AAA for external)
        >CS VIP (without AAA for internal)
        – > LB VIP for SMTP and IMAP (without AAA for internal)
        – > LBs 0.0.0.0 for OWA, autodiscover, … (with AAA for external)
        Is this a clean and supported solution or is there some mistake?
        Or can this be done with CS policies (for internal and external clients) an the same CS forwarding to different LB VIPs?
        Thank you again 🙂
        Greetings Kevin

        Like

      2. You Need to setup vServer with and without AAA enabled. You are correct 😉
        – lb_owa_external
        – lb_owa_internal
        In big environments you normaly have an internal NetScaler pair and can just create a Service on the DMZ NS which is pointing to the internal OWA LB. Then Setup a LB vServer, specify the Service (Internal) and enable AAA.
        Greets
        Julian

        Like

      3. Hi Julian,
        Thank you for your answers so far. They help me a lot to get deeper into Netscaler.
        So I only need two different LB vServers (one for OWA internally without AAA and one for OWA externally with AAA).
        But what would a policy look like at CS VIP that can distinguish whether request is for internal or external OWA LB vServer?
        Or is a second CS needed just for external requests?
        Greetings Kevin

        Like

      4. Method 1 – You could create CS Policy which is filtered by the requested Hostname/URL and the Client Source IP (CLIENT.IP.SRC.IN_SUBNET(x.x.x.x/x)
        Method 2 – Create a second CS and Point internal DNS requests to this VIP

        Like

  6. Hi Julian,

    Great blog. This is far better explained and indepth than what the “official” Citrix documentation recommends.

    One question:
    In your scenario you use one IP address for the HTTP/HTTPS Content Switch and another IP address for SMTP and IMAP.
    Presumably this means that Outlook and OWA would connect to one DNS A record (e.g. mail.domain.com) and SMTP and IMAP would connect to another (e.g. smtp.domain.com).

    Is it possible to use just one IP address for HTTP, HTTPS, SMTP and IMAP?

    The reason I’m asking is because there are currently around 300 servers and printers using SMTP relay to send email to a plethora of different DNS entries pointing at the old Exchange environment and it’d be quite a daunting task to update them to point at the correct DNS A record that is pointing at the SMTP/IMAP load balanced VIP.

    Kind regards
    David

    Like

    1. Of course, you can create a Content Switch with the IP 192.168.2.240 (HTTPS) and a Load-Balancing vServer using the same ip address with your SMTP/IMAP ports. Keep in mind: You can not use the same port for a single ip address.
      Valid:
      CS – 192.168.2.240 – SSL – 443 (OWA)
      LB – 192.168.2.240 – TCP – 25 (SMTP)
      LB – 192.168.2.240 – TCP – 143 (IMAP)
      Not valid:
      CS – 192.168.2.240 – SSL – 443 (OWA)
      LB – 192.168.2.240 – TCP – 443 (SMTP)
      LB – 192.168.2.240 – TCP – 143 (IMAP)

      Like

  7. Excellent article Julian!
    I am running into a little authentication issue with this setup, and I was hoping you can guide me in the right direction, we are not using any of the features highlighted in 4.7, 4.8 and 4.9. I also added an entry for the powershell virtual directory.
    Phones, OWA and ECP are working as expected but the Outlook clients (2010 and 2016 in online mode because we use Citrix lol) keep prompting for credentials and for some reason I can’t get passed that. I was able to connect once using Outlook 2010 but as soon as I closed it I was challenged with the credentials prompt again.
    Any ideas? Do we need to enable AAA?
    Thanks a lot!

    Like

    1. You don’t need AAA. It’s only for improved security implementation. Can you see a failed login attempt in the Exchange Security eventlog? Are you using NTLM or Kerberos authentication for RPC/MAPI?
      Julian

      Like

      1. Thanks for getting back to me so soon.
        Unfortunately the logs already rolled, but I’ll try to catch it tonight.
        What I noticed is that the MAPI virtual directory on one of our Exchange servers is set to Ntlm,Negotiate,OAuth and the other one for some reason is set to Ntlm,Negotiate, I’m going to make sure both are set to Ntlm,Negotiate,OAuth and then try this exercise again, thanks for the tip.
        We are still in the middle of the migration so we also have some RPC connections going back to the Exchange 2010 CAS servers for Public Folder access, there is an lb vserver (*/any) going to back to the CAS servers that will decommissioned once the migration is completed, could this be a factor as well?
        Thanks again.

        Like

      2. Julian,
        I was able to bypass the Outlook authentication issue by setting the MAPI persistence to SOURCEIP as defined here: https://www.citrix.com/content/dam/citrix/en_us/documents/guide/deploying-netscaler-with-microsoft-exchange-2016.pdf
        I definitely like your approach a lot more, but couldn’t figure out what was preventing me from logging in, I saw the header in Fiddler and that’s what made me switch the persistence.
        Any thoughts?
        And again many thanks!

        Like

  8. Hi Julian,
    Little mistake at the commands at chapter 4.8
    #Enable Front End Optimization
    enable ns feature FEO
    #Front End Optimization
    #Replace FQDN
    add feo policy feo_pol_exchange2016 ‚HTTP.REQ.HOSTNAME.CONTAINS(„mail.flashmob-saulgau.de“)‘ MODERATE
    bind lb vserver cs_exchange2016_ssl -policyName feo_pol_exchange2016 -priority 100
    I think you would like to bind the FEO Policy to the CS vServer, not a LB vServer, so
    bind cs vserver cs_exchange2016_ssl -policyName feo_pol_exchange2016 -priority 100
    would be correct.
    Thanks for your article, very good Job!
    Regards
    Julian 😉

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

Up ↑

%d bloggers like this: