This is something that had me stumped since Thursday. I was this close to having my Citrix implementation accessible externally via a NetScaler gateway, but it wasn’t working. What was the issue? The ICA file did not have the gateway address, it only contained the internal address of the VDA and obviously that isn’t reachable over the Internet.
The ICA file had this (an internal address) (FYI: you can enable ICA logging to get a copy of the ICA file):
1 |
Address=10.126.31.196:1494 |
While it should have had something like this (STA info along with the external address of my gateway):
1 2 |
Address=;42;STA343530117;D1B5869135ED230DBFA95E563F8B68;STA906839512;DBA68EAF468E90456AEDE31F1CFBD8 SSLProxyHost=mygateway.fqdn |
Everything was configured correctly as far as I could see, but obviously something was missing.
First question: who generates the ICA file? As far as I know it is the StoreFront, but was I sure about that? Because whoever was generating the ICA file wasn’t doing a good job of it. Either they were wrongly detecting my external connection attempt as coming internally and hence skipping out the STA etc. information, or they knew I was connecting externally but choosing to not input the gateway information. Found this excellent blog post (cached PDF version just in case) on the flow of traffic and that confirmed that it is the StoreFront who generates the ICA file.
- Upon login via NetScaler (or directly) the StoreFront creates a page with all the available resources.
- User clicks on a resource. This request makes its way to the StoreFront server – either directly or via NetScaler.
- StoreFront contacts the XML/ STA service on the Delivery Controller which will decide where to launch the resource on (which server/ desktop etc).
- The XML/ STA service will put all this information in an STA ticket (basically an XML file) and send back to the StoreFront server.
- The StoreFront will create an ICA file and send to the user. The ICA file is based on a template, per store, and can be found at
C:\inetpub\wwwroot\Citrix\<store>\App_Data\default.ica
.- Depending on whether the connection is internal or via gateway the StoreFront server will put in the correct address in the ICA file. (We will come back to this in a bit)
- The StoreFront passes this ICA file to the gateway if its an external connection, or to the receiver / browser directly if its an internal connection.
Ok, so the StoreFront is the one who generates the ICA file. So far so good.
How does the StoreFront know the connection is via a gateway? There’s this thing of “beacons” which is supposed to help detect if a connection is external or internal but that’s used by the receiver, not by the StoreFront. Basically a store has an internal URL and an external URL (via gateway) and once you add a store to Citrix Receiver the Receiver uses beacons to identify if its internal or external and use the correct URL. Note: this is for connecting to a store – i.e. logging in and getting a list of resources etc, nothing to do with ICA files or launching a resource (which is what I am interested in).
StoreFronts have a list of gateways corresponding to the various NetScaler gateways that can connect to its stores. Each gateway definition contains the URL of the gateway as well as a NetScaler SNIP address (now optional; the article I link to is a good read btw). When a connection comes to the StoreFront it can match it against the gateway URL or the SNIP (if that’s defined) and thus identify if the connection is external or internal. (When a user connects through, the StoreFront will attempt to authenticate it against the gateway URL so make sure your StoreFront can talk to the gateway. Also, if the gateway URL has a different IP and you can’t modify DNS with the internal IP, then put an entry in the hosts file).
So how to find out whether my connections via gateway were being considered as internal or external? For this we need to enable debug logging on the StoreFront.This is pretty straight-forward actually. Log on to the StoreFront server, open PowerShell with admin rights, and run the following cmdlets:
1 2 |
Add-PSSnapin Citrix.DeliveryServices.Framework.Commands Set-DSTraceLevel -All -TraceLevel Verbose |
Then we need to download DebugView from SysInternals and Click Capture and select Capture Global Win32
. In my case I could see in the debug console straight away that the connection was being detected as external:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
[8592] Request data: [8592] XCitrixGateway= [8592] XCitrixVia=mygateway.fqdn [8592] XCitrixViaVip=<NS SNIP> [8592] XForwardedFor=<external ip>,<internal ip> ... [8592] Token data: [8592] XCitrixGateway= [8592] XCitrixVia=mygateway.fqdn [8592] XCitrixViaVip=<NS SNIP> [8592] XForwardedFor=<external ip>,<internal ip> [8592] RemoteAddr=127.0.0.1 [8592] CitrixTrustCertRef= [8592] Identified Gateway=<gw name>Configuration data: ... [8592] Detected gateway: '<gw name>' |
Hmm, so all good there too. StoreFront was definitely detecting my connection as external and yet not putting in the gateway address.
At this point I hadn’t enabled access from my NetScaler to the internal VDAs (because I hadn’t reached that stage yet). So I modified my firewall rules to allow access from the NetScaler SNIP to my XenApp subnet. Still no luck.
On a side note (something which I wasn’t previously clear on and came about while reading on this issue): when defining a gateway on the StoreFront the Callback URL is optional and only required for SmartAccess. Basically a NetScaler gateway can work in Basic/ ICA proxy mode or SmartAccess (full VPN?). I was using the gateway as an ICA proxy only so there was no need for the Callback URL (not that removing it made any difference in my case!).
Also, if you are using two-factor authentication on the gateway then the logon type in the gateway definition should say “Domain and security token”.
This blog post by the amazing Carl Stalhood on StoreFront configuration for NetScaler gateway is a must-read. If nothing else it is a handy checklist to make sure you haven’t missed anything in your configuration.
Also a quick shout-out to this great post on troubleshooting NetScaler gateway connection issues. It is a great reference on the whole process of connection as well as the ICA file and what you can do at each step etc. (One of the things I learnt from that post is that apart from the STA ticket the ICA file also contains an NFuse ticket – this is the previous name of Citrix StoreFront/ Web Interface and is found as a line LogonTicket=
in the ICA file).
And since I am anyways linking to two great posts at this point, I’d like to re-link to a post I linked to above (from Bas van Kaam) explaining the XenApp logon flow etc.
Anyhow. After a whole lot of Googling I came across this forum post (in all fairness, I came across it as soon as I had started Googling, but I mis-read the suggestion the first few times). It’s a cool thing, so I’d like to take a moment to explain first before going on into what I had mis-configured.
At the firm where I work we have multiple sites. Each site has its own infrastructure, complete with Delivery Controllers, StoreFronts, and NetScaler gateway. Users of each site visit their respective gateway and access their resources. There’s nothing wrong with this approach just that it is kind of unnecessary for users to keep track of the correct URL to visit. We actually have a landing page with the gateway URLs of each of our sites and users can click on that to go to the correct gateway.
It makes sense to each site to have its own resources – the XenApp/ XenDesktop servers. It also makes sense to have separate Delivery Controllers per site – so they are close to the resources. And it makes super sense to have a NetScaler gateway per site so that user connections go from their remote location (e.g. home) to the site gateway to the XenApp/ XenDesktop resource. But we don’t really need separate StoreFront servers do we? What if we could have the StoreFront servers in a single location – serving all the locations – yet each user’s connecting to the resources in their location go via the NetScaler gateway in that location? Turns out this is possible. And this feature is called Optimal HDX Routing.
- We would have a NetScaler gateway in a central site. This site would also have a bunch of StoreFront servers.
- Each non-central site would have its own Delivery Controllers with VDA infrastructure etc.
- On the StoreFront servers in the central site we define one or more stores. To the stores we associate the Delivery Controllers in all the other sites.
- At this point a user could login to the gateway/ StoreFront in the central site and potentially connect to a resource in any of the sites. This is because the StoreFront is aware of the Delivery Controllers in all the sites.
- I am not entirely clear which Delivery Controller the StoreFront would query though to get a list of resources (coz I am still figuring out this stuff). My feeling is this is where the concept of zones come in. I think once I create a zone I’d be associating users and Delivery Controllers to it so that’s how the StoreFront knows whom to contact.
- The StoreFront server in the central location passes on this info to its gateway (i.e the one in the central location).
- (fast-forwarding a bit) Say its a user in a remote site and they select a resource to use (in the remote site because they are mapped to it via zones). The request is sent to the StoreFront in the central location.
- At this point the StoreFront can launch the resource via the Delivery Controller of the remote site. But how should the user connect to this resource though? Should it connect via the NetScaler gateway in the central site – inefficient – or is there a way we can have a NetScaler gateway in each remote site and have the user connect via that?
The answer to that last question is where optimal HDX routing comes in. StoreFront doesn’t know of zones (though you can mention zones for info I think) but what it does know is Delivery Controllers. So what a StoreFront can do – when it creates an ICA file for the user – is to look at the Delivery Controller that is serving the request and choose a NetScaler gateway which can service the request. The StoreFront can then put this NetScaler gateway address in the ICA file, forcing the user to connect to the resource in the remote site via that remote NetScaler gateway. Neat huh!
I don’t think I have explained this as best as can be done so I’d like to point to this blog post by JG Spiers. He does a way better job than me.
Here’s what the issue was in my case. Take a look at this screenshot from the Optimal HDX Routing section –
Notice the default entry called “Direct HDX connection” and how it is currently empty under the Delivery Controllers column? Well this entry basically means “don’t use a gateway for any connections brokered by the listed Delivery Controllers” – it’s a way of keeping a bunch of Delivery Controllers for non-gateway use only. For whatever reason – I must have been fiddling around while setting up – I had put in both my Delivery Controllers in this “Direct HDX connection” section. Because of this even though my StoreFront knew that the connection was external, since the entry for my gateway (not shown in the screenshot) had no Delivery Controllers associated with it the StoreFront wasn’t returning any gateway address. The fix thus was to remove the Delivery Controllers from the “Direct HDX connection” section. Either don’t assign the Delivery Controllers to any section, or assign it to the entry for my gateway.
Here’s similar info from the Citrix docs. I still prefer the blog post by JG Spiers.
Took me a while to track down the cause of this issue but it was well worth it in the end! :)
Update: From a blog post of Carl Stalhood:
If you have StoreFront (and NetScaler Gateway) in multiple datacenters, GSLB is typically used for the initial user connection but GSLB doesn’t provide much control over which datacenter a user initially reaches. So the ultimate datacenter routing logic must be performed by StoreFront. Once the user is connected to StoreFront in any datacenter, StoreFront looks up the user’s Active Directory group membership and gives the user icons from multiple farms in multiple datacenters and can aggregate identical icons based on farm priority order. When the user clicks on one of the icons, Optimal Gateway directs the ICA connection through the NetScaler Gateway that is closest to the destination VDA. Optimal Gateway requires datacenter-specific DNS names for NetScaler Gateway.
That clarifies some of the stuff I wasn’t clear on above.