The cloud makes it possible for us to have effortless access to our data from any device. Users have adapted quickly to this concept and expect to have the same experience when accessing company-managed data. However, certain industries still need to follow strict compliance and security regulations, which require data to be stored locally.

ShareFile‘s support for on-premises storage zone controllers fits perfectly into Citrix’s Hybrid Cloud strategy: it provides a unified experience for end users and flexibility for administrators. To make this happen, we need a strong and secure bridge between the on-prem and cloud environments; a task that’s just right for Citrix NetScaler.

To help you set up NetScaler for ShareFile with on-premises storage zone controllers, an easy-to-use wizard is included in the GUI. This article will guide you through the manual configuration of NetScaler, explaining each step in detail. My goal is to provide more insight into how NetScaler handles secure access to your local files. A good understanding of all traffic flows and components can be helpful when there is a need to troubleshoot and detailed documentation may be required for security audits. As a bonus, those who have little experience with NetScaler will get to know some of its more advanced capabilities and may discover opportunities to leverage these features for other kind of deployments.

Getting started: components and terminology

Pre-requisites and assumptions

  • Networking already configured according to best practices
  • Required Firewall rules in place
  • DNS records configured for the external address for ShareFile. I will use in my examples – IP:
  • Public SSL Certificate (CA signed) for your external ShareFile URL installed on NetScaler. (wildcard can be used)
  • Two configured Storage Zone Controllers in the internal network: lab-szc1.ctxtestlab.local – IP: and lab-szc2.ctxtestlab.local – IP:
  • SSL offloading on NetScaler
  • Advanced expressions are used in the guide (classic expressions can still be used).

The high level overview

For those not familiar with NetScaler terminology, let’s start with listing and explaining the components that will be used. Netscaler allows you to configure different types of Virtual Servers (VS). Each VS can be assigned an IP address or can be configured as non addressable, meaning they cannot be reached directly from within the network, but Netscaler can internally access them.

  • 1 Content Switching Virtual Server (CSVS): external connections will first hit the CSVS. This VS will be configured with the external IP address (or NAT address). The goal of a CSVS is to direct requests to another VS based on policies you configure. It allows you to use a single (external) IP to access multiple virtual servers and/or services.
  • 3 Content Switching Policies (CSPOL): We will configure three content switching policies, one for each of our load balancing virtual servers and bind it to our CSVS. Based on an expression, for example ‘Does the requested URL contains /cifs/ in the path?’ we can determine the appropriate action, e.g. sending it to the correct load balancing virtual server.
  • 3 Load Balancing Virtual Servers (LBVS): a LBVS provides load balancing and fault tolerance to services. For ShareFile, these VS will ensure a HA connection to our internal storage zone controllers. Why three of them? I will come back to this later on. A LBVS can do more than just fault tolerance and we will make use of these possibilities later on.
  • 1 Service Group (SG): a service group enables us to manage a group of services as. For ShareFile integration, we will add a HTTP service group with both our Storage Zone Connectors as members. A SG can be bound to a LBVS.
  • 1 Monitor (MON): a monitor checks the health of a service or SG member to make sure a server/service is marked offline and excluded from load balancing when an issue is detected. This can be a simple ping or we can check HTTP response codes, analyze a GET request etc. We will bind a monitor to our SG.
  • 2 Servers: we will define our two Storage Zone Connectors as servers based on local IP address or hostname.
  • 1 Repsonder Policy (RPOL): this type of policy can be bound to a LBVS and allows us to change the HTTP response our VS sends back based on conditions we can specify in an expression. In our case, we will use an RPOL with an action to drop traffic if URI validation fails.
  • 2 HTTP callouts (HTTPC): these will be used in our RPOL expression. A HTTPC will make a HTTP request from Netscaler to an external service, independently from the original request to the VS. The response received will be parsed and a simple value (in most cases a Boolean) will be returned. In our setup, two HTTPC’s will be used to validate the URI’s and protects us from man in the middle attacks.
  • 1 Authentication Virtual Server (AAA) or Netscaler Unified Gateway Virtual Server (GWVS): this VS will take care of authentication. When integrating with an existing XenApp/XenDesktop deployment we can leverage the GWVS for authentication as well.

For those not very familiar with Netscaler, the amount of different terms and components can be a bit overwhelming at this point. To keep the overview, I’ll link them together in this chart:

The tale of three load balancing virtual servers

When looking at above drawing, you might have noticed that all three load balancing servers have the same service group bound containing our Storage Zone Connectors (SZC). So why three? The reason is that  files can be downloaded and uploaded:

  • To personal and shared folders in the on-premises Storage Zone. This includes the File Box folder used for sharing files through a public link or via email.
  • To a local CIFS shares and SharePoint accessed through connectors.

Data in the onprem Storage Zone is stored on a dedicated internal share. The data is accessed using a service account you configure during the SZC setup. Authentication (with a Sharefile account or through SAML) and authorization is handled by the Sharefile control plane and SZC.

CIFS and SharePoint connectors on the other hand require the user to authenticate also against the file or SharePoint server. Remember, ShareFile is not aware of AD credentials. This is where a Netscaler AAA authentication virtual server or NetScaler Unified Gateway VS can help out .

Because we will bind our responder policies and authentication virtual servers at load balancing virtual server level, we need to create a LBVS for Sharefile traffic with the RPOL bound and one for our connector traffic with the authentication server bound to it.

So, that makes two, what is the purpose of the third one? Looking back at our drawing, we see LBVS2 has no AAA servers nor RPOLs. In practice, this means that all traffic will flow through, unauthenticated. URI validation through HTTP callouts cannot be used for CIFS/SharePoint connectors, so we use an alternative method to ensure the ShareFile control plane only communicates with your local SZC’s: Cross-origin Resource Sharing (CORS). CORS uses the OPTIONS method to do a preflight check validating the domain trust before sending any user credentials. Because the preflight check needs unauthenticated access to our SZC’s, without URI validations, a third LBVS is required that will be exclusively used for this purpose.

Managing the traffic — Content switching

To make sure all requests to our SZC are forwarded to the appropriate load balancing virtual server, all requests to our external Sharefile hostname will arrive first at our content switching virtual server.

Using content switching policies, we analyze the HTTP request. If an expression is matched, it is send to the corresponding LBVS, if not, the next policy is evaluated:

  1. The request method is OPTIONS -> CORS preflight check and forward to LBVS2 for unauthenticated access to the CIFS share.
  2. The requested URL contains /cifs/, /sp/ or /ProxyService/ -> forward to LBVS3 and authenticate the users for access to a local CIFS share or SharePoint through a connector. When the user is authenticated, forward the request to the internal SZC to handle access to the data.
  3. The request URL does not contain /cifs/, /sp/ or /ProxyService/ -> a request is made to access ShareFile data in the on-premises storage zone (personal folder e.g.) and is forwarded to LBVS1. URI validation is done through the responder policy and HTTP callouts and if validated, the request is forwarded the SZC internally to provide access.

The cifs, sp and ProxyService folders we look for in the path of the url reflect the application subfolders we can find in IIS management console on a SZC. The web application in the cifs folder handles request to local file shares, the sp folder contains the Sharepoint connector and the ProxyServer is used to proxy local CIFS shares when accessed through a browser.

Time to get our hands dirty – Configuring NetScaler manually

Now we have most of the theory covered, let’s start the configuration. In this guide we will use the GUI to configure all components. I will however not use the wizard for ShareFile to be able to demonstrate how each component works. Because in our flow chart each component is interconnected, it is easier to start at the base and work our way up to the top.


First we define our servers to be used by the service groups. These are our Storage Zone Controllers. In the left menu of the Netscaler GUI’s Configuration tab, navigate to:

Traffic Management → Load Balancing → Servers. Click Add.

Name your server (you can choose any name, I use the FQDN), enter the internal IP address and click Create.

Repeat for the second storage zone controller.


Being able to ping a server does not mean the desired service is available. This is why we included a heartbeat into the SZC. In practice, we configure our monitor to send a HTTP GET request to the SZC (/heartbeat.aspx). The SZC will respond with ****ONLINE**** if all services and components are healthy. If the monitor receives any other value or a timeout, the SZC will be flagged as offline and load balancing will exclude the server. To add the monitor:

Traffic Management → Load Balancing → Monitors. Click Add.

Give it a name, select type HTTP-ECV and fill in the send string:

GET /heartbeat.aspx

and receive string:


And click on the Create button at the bottom.

Service group

We have no everything we need to create our Service Group. Navigate to:

Traffic Management → Load Balancing → Service Groups. Click Add.

Give it a name, keep HTTP as the protocol (we will offload SSL) and click OK. (leave all other settings default as well)

Click on No service Group Member and a popup will appear. Select the option Server Based, click Click to select and check the first SZC server in the list and click the Select button on top. Fill in 80 in the port text field.

Repeat for the second SZC.

Click the OK button and from the Avanced Settings menu on the right, click Monitors.

Add the heartbeat monitor, click the Select Monitor Field, check the one we created before in the list and click Select on top and click Bind.

Click Done to finish the SG configuration.

Load Balancing Virtual Servers

LBVS1: ShareFile Data

We need three of them so let’s start with the first one that will be used for on-premises ShareFile data (files in user’s folders not accessed through connectors).

Traffic Management → Load Balancing → Virtual Servers. Click Add.

Give it a comprehensive name, select SSL as protocol and set the IP Address Type to Non Addressable and click OK. We will use content switching to address the LBVS internally so there is no need to assign an IP address.

Now we bind our service group to it. Click No Load Balancing Virtual Service group, Select name, check the one we created before in the list and click Select on top. Then click Bind and Continue.

Next is the certificate. Click No Server Certificate, and select the certificate corresponding to the FQDN for external access. A wildcard certificate can be used as well. Click Bind and Continue.

The LBVS is now online. We continue the configuration from the advanced menu on the right to set up Method and Persistence.

Configuring method and persistence we will ensure that multiple requests made in the same session will be handled by the same SZC. We don’t want two requests for the same action sent to two different controllers as they will not now about each other’s requests.

Configure the Token method and define a expression:


And click OK. When a user uploads a file to one of his folders (not including connectors), the Sharefile control plane will include a unique upload ID in the request URL. In our example, the URL can look like…&uploadid=44454545

The requests that follow for the same upload will contain the same id and the LBVS will ensure they will be forwarded to the same SZC.

As SSL is a requirement, persistence can be easily configured using the SSL session. Select the Others option and SSL Session with timeout of 2 minutes and click OK.

LBVS2: Connectors – CORS preflight check

The next LBVS we create is the one used for CORS (OPTIONS method) when accessing a connector to a local share or SharePoint. Create this one exactly like the first LBVS (SSL, non addressable, bind the same service group and certificate). The only exception is that you can skip the method and persistence part.

LBVS 3: Connector data

We create our final LBVC again identical to the first one, except for method and persistence (SSL, non addressable, bind the same service group and certificate)

For this one, we configure persistence COOKIEINSERT with a timeout of at least 10 minutes. You can choose a longer timeout value to find a balance between security and user experience. After the timeout, the user will need to authenticate again when accessing a connector.

To conclude the load balancing server part, we can bind an authentication server to this LBVC for connector traffic. This step is optional, as you can leave the authentication up to the file or SharePoint server internally. It is however recommended to let Netscaler handle the authentication as this is more secure and we can make use of SSO features.

Click on Authentication in the advanced menu on the right and select 401 based authentication and select the authentication virtual server to use. This can be a AAA VS or a Netscaler Gateway VS.

I will not go into detail on how to configure authentication virtual servers in this article as this will lead us too far. Remember to bind a session profile and policy for SSO to the authentication server you use.

HTTP Callouts and Responder

Now it is time to pat yourself on the back for the hard work already done and reward yourself with a well-deserved coffee (or tea if you prefer). The next steps won’t take much of your time to configure, but a fresh mind is recommended as it gets a bit more complicated.

We will now configure the URI validation mechanism and bind it using a responder policy to our first LBVS (Sharefile data). This will ensure that only requests from your Sharefile control plane can access your internal Storage Zone Controllers and prevents man in the middle attacks. Remember, there is no more additional authentication so this is important.

For URI validation, we will configure two HTTP callouts that will send a HTTP GET request to our load balancing virtual server (and in turn to the SZC) and return a boolean based on an expression on the response received from the SZC.

Navigate to:

AppExpert → HTTP Callouts and click Add

Name the first one sf_callout, send the request to a Virtual Server and select your first LBCV (Sharefile data).
As host expression, set it to the internal ip address of any of your SZVC. Configure the URL Stem expression as follows:


Scrolling, down make sure the scheme is set to HTTP, return type BOOL and the expression to extract:


Then, configure the second callout exactly like the first, name it sf_callout_y. The only difference is the URL Stem Expression. Set it to:


We will use our fresh callouts in a responder policy. Navigate to:

AppExpert → Responder → Polices and click Add

Name your policy, select DROP in the action dropdown menu and configure this expression (notice we call our HTTP callouts):

HTTP.REQ.URL.CONTAINS(“&h=”) && HTTP.REQ.URL.CONTAINS(“/crossdomain.xml”).NOT&& HTTP.REQ.URL.CONTAINS(“/validate.ashx?requri”).NOT&& SYS.HTTP_CALLOUT(sf_callout) || HTTP.REQ.URL.CONTAINS(“&h=”).NOT && HTTP.REQ.URL.CONTAINS(“/crossdomain.xml”).NOT&& HTTP.REQ.URL.CONTAINS(“/validate.ashx?requri”).NOT&& SYS.HTTP_CALLOUT(sf_callout_y)

Click Create and return to your Load Balance Virtual servers list via the menu:

Traffic Management → Load Balancing → Virtual Servers

Click on your first LBVC (Sharefile data), in the advanced menu on the right click on Policies. A policies field will be added on the bottom of the settings page of your LBVC. Click the + sign in the top right hand corner.

Select Responder and Request Type:

Click Continue, click on the Select policy box, check the policy we created, click on Select on top.

Keep all default settings and click Bind.

Click Done to close the properties of our LBVC.

This conlcudes the practical part, sit back and let’s analyze what we just configured.

We have created two HTTP callouts, used them in a responder policy expression with action DROP and bound the policy to our LBVC that will handle ShareFile data. Consider this scenario: a user uploads a file to his personal folder stored in the on-premises zone, the request will be forwarded to LBVC1 and the expression of the bound responder policy will be evaluated. This means that if the expression of the responder policy resolves to true, traffic will be dropped and the request will never reach our SZC.

Let’s have a look at that responder policy expression again:

HTTP.REQ.URL.CONTAINS(“&h=”) && HTTP.REQ.URL.CONTAINS(“/crossdomain.xml”).NOT&& HTTP.REQ.URL.CONTAINS(“/validate.ashx?requri”).NOT&& SYS.HTTP_CALLOUT(sf_callout) || HTTP.REQ.URL.CONTAINS(“&h=”).NOT && HTTP.REQ.URL.CONTAINS(“/crossdomain.xml”).NOT&& HTTP.REQ.URL.CONTAINS(“/validate.ashx?requri”).NOT&& SYS.HTTP_CALLOUT(sf_callout_y)

Notice the ||, OR, in the middle, so traffic will be dropped if ALL (&&) conditions left of || resolve to true OR all conditions right of the || are true. AND will take priority over OR. Also, Netscaler’s intelligence stops evaluating the consecutive AND conditions if one is false. As a result, a callout is not triggered when configured as the last of a consecutive series of AND’s and there is at least one prior condition false. This will save useless actions, transactions and resources.

HTTP.REQ.URL.CONTAINS(“/crossdomain.xml”).NOT is present on both sides of the ||. So when this xml file is requested, the request is always forwarded to your SZC. This is required because we need to be able to read out domain information before we can validate the URI’s.

We also see a HTTP.REQ.URL.CONTAINS(“/validate.ashx?requri”).NOT condition on both sides.
Looks familiar? This is part of the Stem URL we configured in our callouts. We trigger the callout in the responder policy, the callout will in turn make a request to the same LBVS1, hit the policy again, and we need to avoid the same callout is triggered again as this will result in an endless loop.

To summarize, the responder expression will only be true (= DROP of traffic) in these two conditions:




Simplifying it even more, traffic will be dropped when:

  • The requested URL contains “&h=” and the response of the HTTP callout sf_callout is true.
  • The requested URL does NOT contain “&h=” and the response of the HTTP callout sf_callout_y is true.

The request will be forwarded to the SZC if:

  • The requested url contains “&h=” and sf_callout reponds false
  • The requested url doesn’t contain “&h=” and sf_callout_y reponds false
  • The request originates from a callout
  • The crossdomain.xml file is requested

To continue our analysis, we need to have a close look at our two callouts: Let’s start with a request without the h query parameter, resulting in triggering sf_callout_y:

We configured that we need to send out a HTTP GET request to our first LBVS (Sharefile data) with this URL Stem:


The HTTP calllout will encounter the same responder policy but the expression will always resolve to false (it contains validate.aspx?requesturi=) so traffic will aways be forwarded to validate.ashx in the root of the IIS website on the SZC. Two query parameters are added as well

  • A query parameter RequestURI with as value the request URL, encoded
  • A query parameter h with an empty value

The SZC will now check if the request is valid. The SZC only accepts requests from the external url specified during setup of the controller. It decodes the url provided through the RequestURI query parameter and will return a HTTP status of 200 when it matches the configured external URL after decoding.

To add another level of security, the h query parameter is added containing a SHA-256 HMAC digest of the path and query string. Remember when setting up your first SZC, you needed to provide a secret? Well, this secret is used for sigining. This secret is known only to the ShareFile control plane and your SZC controllers. All upload and download requests will include a h parameter with a value only your SZC’s that know the secret can decode.

Because this parameter is not considered as a part of the actual request url, we need to exclude it from the url encoding in our callout and return the encoded request URL with the h parameter not encoded at the end if the url. This explains why we need an additional callout that takes into account the h parameter.

The responder policy expression states that we need to trigger sf_callout when &h is present in the request URL: HTTP.REQ.URL.CONTAINS(“&h=”)&& SYS.HTTP_CALLOUT(sf_callout)

This callout is identical to sf_callout_y, with the exception of the URL Stem expression:


The control plane adds the h parameter to the request url. Because the SZC expects the RequestURI parameter to contain the encoded request url without the digest (h).
HTTP.REQ.URL.BEFORE_STR(“&h”).HTTP_URL_SAFE.B64ENCODE strips off the h parameter before encoding and + “&h=”+ HTTP.REQ.URL.QUERY.VALUE(“h”) adds the untouched h parameter at the end of the encoded URL.

The SZC controller will now validate the request url:

  • Using the original digest value added by the control plane, the value of the h parameter, decoded using the shared secret. This prevents man in the middle attacks between the Sharefile control plane and your environment.
  • Using the encoded value of RequestURI, preventing man in the middle attacks between Netscaler and SZC. An internal device could intercept the h value and pretend to be the Netscaler.

When the SZC validates the request, it will respond with HTTP 200 Status to the callout. This status is then evaluated with the expression we configured: HTTP.RES.STATUS.EQ(200).NOT

In practice, this means that when validation is ok, the responder policy will receive boolean false as response from the callout. This is a bit confusing, but remember that our responder policy will DROP if the end result of the expression is true,  so in this case false means it’s ok.

To help you digest this information, I have tried to visualize the process with an example:

The ShareFile control plane requests to upload a file to a personal folder stored in the on-prem storage zone and sends a request to your external Sharefile on-prem address:

Request URL =
Where h
= encoded value of the request url signed with the client secret.

  1. Request is forwarded to the Load Balancer VS for ShareFile Data (content switching) and the first part of consecutive AND conditions is triggered: HTTP.REQ.URL.CONTAINS(“&h=”) && HTTP.REQ.URL.CONTAINS(“/crossdomain.xml”).NOT&& HTTP.REQ.URL.CONTAINS(“/validate.ashx?requri”).NOT&& SYS.HTTP_CALLOUT(sf_callout)
  2. The responder policy is evaluated: url does contain a h value (true), does not contain /crossdomains.xml (true), does not contain validate.ashx?RequestURI(true)
    1. Next evaluation is the HTTP callout so sf_callout is triggered. The URL stem expression results in: /validation.ashx?RequestURI=<encoded request url without h>&h= fes4TE4DG44GSGDFRG
    2. HTTP GET request is made to the LBVS internally with request URL /validation.ashx?RequestURI=fefes56ff48eeFFEZ&h= fes4TE4DG44GSGDFRG
    3. Callout request is evaluated by responder policy (separately from the orginal request, this one is still waiting on the response of the callout). The url contains /validation.ashx?RequestURI so we know the expression is false and there is no need to trigger callouts -> no drop and request is transfered to the SZC.
    4. The SZC validates if both the RequestURI and the h value are valid and the request originates from the configured external url and the Sharefile control plane.
    5. The SZC send a HTTP 200 status to the sf_callout. The response is evaluated using expression: HTTP.RES.STATUS.EQ(200).NOT. We did receive a HTTP status 200 response, and because of the ‘.NOT’ the callout returns Boolean false to the responder policy.
  1. The HTTP callout cycle is now complete and the responder policy expression got the response for the last condition (the callout). We can now finish the responder expression evaluation of the original request. This is what we had already:
    • Contains &h → true &&
    • Does not contain /crossdomains.xml → true &&
    • Does not contain validate.ashx?RequestURI → true &&
    • Now adding the callout response: false 

The responder expression right of the OR will be false right away because the first condition checks if there is no “&h”.

The result of the whole expression of the responder policy will be FALSE: do not DROP and forward request to SZC. This is what we expect: the request URI is valid, the h value as well so the request can be safely forwarded to our SZC.

Content switching

Good news, the most complex part is finished and we only have one small task to do before we can start testing: configuring our content switching polices and virtual server.

As we have three LBVS’s, we configure three content switching policies. Navigate to:

Traffic Management → Content Switching → Policies. Click Add.

We start with a content switching policy for CORS. We know CORS uses HTTP method OPTIONS only, so give it a name and use following expression:


Note that I also include a hostname check in the expression. This will already drop any request not made to the chosen external hostname and it allows us to reuse the external IP for other services using anotherhostname pointing to the same external IP, if we would needs to do so in the future.

Click Create and add another one for connector data (cifs and sharepoint) with expression:


If the request is made to our external hostname for Sharefile AND the requested URL contains /cifs/ OR /sp/ OR /ProxyService/, the expression will evaluate to true.

The last one is for requests to the Sharefile Data LBVS:


Will be true for requests to our external hostname not containing /cifs/, /sp/ and /ProxyService/.

Now we will bind them to a Content Switching Virtual server we will create. Navigate to:

Traffic Management → Content Switching → Virtual Servers. Click Add

Give your CSVS a name, select SSL protocol and assign the external IP address. This is the public IP address the hostname of your external ShareFile resolves to or the NAT address. Port 443 is required.

Click on OK and No Content Switching Policy Bound to add our CSPOLs. Start with the first (pol_cs_sf_connector_options), select the second LBVS you configured (without authentication and responder policy) as target and click Bind.

Add the second policy the same way (pol_cs_sf_connector_data) and select the third LBVS (with authentication) followed by pol_cs_sf _data with the first LBVS as target (no authentication but with the responder policy bound).

If you add them in the I order specified, the priorities should be set correctly automatically. A policy with a lower priority number will be handled first. If the expression evaluates to true, the request if forwarded to the target LBVS and policies with a higher priority number will be disregarded.

Your CSPOL bindings should look like this. If priorities are not right, you can select a policy, edit the binding and change the priority:

The final action is to bind our certificate to the CSVS as well. Click Certificate in the advanced settings menu on the right and bind the server certificate the same way as binding it to a LBVS.

Your CSVS settings page should now look like this:

If it does: congratulations, you have set up your NetScaler manually for ShareFile on-premises!

Logon to your ShareFile subdomain, check if your on-prem zone is online and healthy and configure a test user’s storage location to the on-prem zone. Happy testing!

Further reading and next steps

There is a lot more Netscaler can do to further integrate ShareFile and to provider secure access and authentication to other types resources in your environment. Integration with XenMobile, unified access to XenApp/XenDesktop published apps, SAML authentication, SSO to intranet apps and I can go on for quite some time. Netscaler is the glue between cloud and on-premises for hybrid cloud solutions.

Citrix TechBytes – Created by Citrix Experts, made for Citrix Technologists! Learn from passionate Citrix Experts and gain technical insights into the latest Citrix Technologies.

Click here for more TechBytes and subscribe.

Want specific TechBytes? Let us know!