NetScaler – Always On Machine & User Tunnel VPN

Reading Time: 7 minutes


Recently I had the pleasure to implement the Always On VPN mechanism from Citrix ADC. As there are three different technical possibilities, I will give you some insights about my deep dive, which should be an extension for Citrix Product documentation or other available posts about this topic.

Citrix ADC’s Always On is a great alternative to often used solutions like Microsoft’s. I think the biggest difference is the protocol – there is no PEAP/IKEv2, everything is handled as SSLVPN, using straight https 443. This can be a benefit when using port-restricted networks like Hotel or Public WiFi.

We have to difference between the following three setup options:

  1. Always On VPN before Windows Logon (aka the machine tunnel)
  2. Always On VPN after Windows Logon (aka the user tunnel)
  3. The combination of 1 + 2 for full Always On capabilities


Server Part

I’ve created a script which is doing most of the configuration, but let’s get into some details, which settings I’m configuring and why.

I’m using two different EPA settings, one scan for the Machine Tunnel and the second when the User Tunnel is auto-established (with SSO). The product documentation is using username + password LoginSchema for SSO, that’s part of the supported Auto-Logon mechanism. My consideration is security – a aser is able to request the AOVPN GW-Page via Browser and is only prompted with username + password, that’s not enough in these days.

Luckily, EPA Device-Cert scan + username and password (which is filled of the Auto-Logon) is working fine. It is also working fine when using a User-Cert instead of Device-Cert scan with EPA. You just have to think about if you would like to enroll a Device and a User-Cert per client.

Next config is to differ Client-IP Pools between Machine Tunnel and User Tunnel, as mostly the Machine Tunnel should only get access to ADS / DNS / Software-Deployment-Servers / RemoteHelp / WSUS / … while User Tunnel get access to different application servers where the user has to work with. I’m creating a local AAA Group called AAA_local_device_tunnel and bind a separate intranet IP range. The AAA group is bound to the Machine Tunnel EPA Scan with the -default EPAGroup command.

#script for creating AlwaysOn VPN Config which includes a Machine-Tunnel and User-Tunnel with separated Client-IP Pools, Auto-Logon and two times EPA Device-Cert Scan
#replace with your Machine-Tunnel Client-IP Pool
#replace with your User-Tunnel Client-IP Pool
#create your own LDAPS action and bind to Adv_Pol_LDAPS Policy
#binding your complete PKI Certificates is a must have for a successful EPA Scan
#use your preferred loginschema XML for UsernameAndPassword.xml
#replace contoso.local with your internal Active-Directory FQDN


#General Settings
add dns suffix contoso.local

#AAA Settings
add authentication vserver AAA_vServer_AO_MachineTunnel_NA SSL -certkeyNames "FRLAB-RootCA,FRLAB-IssuingCA"
add authentication authnProfile AAA_Prof_AO_MachineTunnel -authnVsName AAA_vServer_AO_MachineTunnel_NA

bind ssl vserver AAA_vServer_AO_MachineTunnel_NA -certkeyName FRLAB-RootCA -CA -ocspCheck Optional
bind ssl vserver AAA_vServer_AO_MachineTunnel_NA -certkeyName FRLAB-IssuingCA -CA -ocspCheck Optional

add authentication epaAction PreAuth_AOVPN_UserEPA_DeviceCert -csecexpr "sys.client_expr(\"device-cert_0_0\")"
add authentication Policy Adv_Pol_AOVPN_UserEPA_DeviceCert -rule true -action PreAuth_AOVPN_UserEPA_DeviceCert

add authentication policylabel NoSchema-ChooseCert -loginSchema LSCHEMA_INT
add authentication loginSchema Schema_OnlyUsernameAndPassword -authenticationSchema "/nsconfig/loginschema/Customer/UsernameAndPassword.xml"
add authentication policylabel LDAP_UsernameAndPasswordOnly -loginSchema Schema_OnlyUsernameAndPassword
bind authentication policylabel LDAP_UsernameAndPasswordOnly -policyName Adv_Pol_LDAPS -priority 100 -gotoPriorityExpression END
bind authentication policylabel NoSchema-ChooseCert -policyName Adv_Pol_AOVPN_UserEPA_DeviceCert -priority 100 -gotoPriorityExpression NEXT -nextFactor LDAP_UsernameAndPasswordOnly

bind authentication vserver AAA_vServer_AO_MachineTunnel_NA -policy Adv_Pol_AOVPN_EPA_DeviceCert -priority 100 -gotoPriorityExpression NEXT
bind authentication vserver AAA_vServer_AO_MachineTunnel_NA -policy Adv_Pol_AOVPN_UserTunnel -priority 110 -nextFactor NoSchema-ChooseCert -gotoPriorityExpression NEXT

add aaa group AAA_local_device_tunnel
bind aaa group AAA_local_device_tunnel -intranetIP
add authentication epaAction PreAuth_AOVPN_EPA_DeviceCert -csecexpr "sys.client_expr(\"device-cert_0_0\")" -defaultEPAGroup AAA_local_device_tunnel
add authentication Policy Adv_Pol_AOVPN_EPA_DeviceCert -rule is_aoservice -action PreAuth_AOVPN_EPA_DeviceCert
add authentication Policy Adv_Pol_AOVPN_UserTunnel -rule is_aoservice.not -action NO_AUTHN

#Gateway vServer Settings
add vpn alwaysONProfile AOVPN-Prof -clientControl ALLOW
add aaa user jakobj
bind aaa user jakobj -intranetIP

add vpn sessionAction VPN_With_SplitTunnel -dnsVserverName LB_vServer_DNS_NA -splitDns BOTH -sessTimeout 480 -splitTunnel ON -localLanAccess ON -transparentInterception ON -defaultAuthorizationAction ALLOW -proxy OFF -clientCleanupPrompt OFF -forceCleanup none -icaProxy OFF -ClientChoices OFF -iipDnsSuffix -WindowsPluginUpgrade Never -MacPluginUpgrade Never -LinuxPluginUpgrade Never -iconWithReceiver ON -alwaysONProfileName AOVPN-Prof
add vpn sessionPolicy ADV_Pol_VPN_With_SplitTunnel true VPN_With_SplitTunnel
bind aaa user jakobj -policy ADV_Pol_VPN_With_SplitTunnel -priority 5 -gotoPriorityExpression NEXT

add vpn vserver GW_vServer SSL 443 -dtls OFF -certkeyNames "FRLAB-RootCA,FRLAB-IssuingCA" -Listenpolicy NONE -authnProfile AAA_Prof_AO_MachineTunnel
bind ssl vserver GW_vServer -certkeyName FRLAB-RootCA -CA -ocspCheck Optional
bind ssl vserver GW_vServer -certkeyName FRLAB-IssuingCA -CA -ocspCheck Optional

add vpn intranetApplication "LAB APP" ANY -netmask -destPort 1-65535 -interception TRANSPARENT
bind vpn vserver GW_vServer -intranetApplication "LAB APP"

save config

Client Part

All Always On VPN settings for the Citrix Secure Access Client are controlled via registry at HKLM\Software\Citrix\Secure Access Client and let’s check the differences and which settings are controlled by ADC when connecting and which you have to set by manual (or controlled via software deployment / GPO / …)

The most important setting is REG_DWORD AlwaysOnService, which isn’t automatically handled by ADC. You have to create the key by manual.

1 = Establish machine tunnel but not user tunnel

2 = Establish machine tunnel and replaced by user tunnel after logon to Windows

Settings for Always On VPN before Windows Logon (aka the machine tunnel):

Always On VPN Registry Machine Tunnel only

The necessary settings are set automatically after the next user-login to the SSLVPN Gateway, so the Machine Tunnel will initiate after next reboot of the client.

This is how the Machine Tunnel looks like on ADC active sessions – the username is the Client-FQDN, this is pulled of the Common Name (CN) field of the device cert. If a device tries to log in with empty CN device certificates, its VPN session is created with the user name as “anonymous”. In a Client-IP Pool (IIP) setup (which I’m always using to differ between AD-Groups and corresponding IP-Pools), if multiple sessions have the same user name, previous sessions are disconnected. So, when IIP is enabled, you notice the functionality impact because of an empty common name.

ADC active sessions Machine Tunnel

Settings for Always On VPN after Windows Logon (aka the user tunnel):

Always On VPN Registry User Tunnel only

The necessary settings are set automatically after the next user-login to the SSLVPN Gateway, so the User Tunnel will initiate after next reboot and Windows-Login of the client, as the Secure Access Client is using the local credentials as SSO. The difference to the Machine Tunnel is the missing AlwaysOnService REG_DWORD

Settings for Always On VPN before Windows Logon (aka the machine tunnel) followed by Always On VPN after Windows Logon (aka the user tunnel):

Always On VPN Registry Machine + User Tunnel

Look and Feel

As already shown in Citrix Product documentation, the Citrix Secure Access Client Logo is appearing in Windows credentials manager, giving information about the Machine Tunnel (aka service mode) connection state:

Machine Tunnel connection state during Windows Logon

After logon to Windows and only using the Machine Tunnel, you will notice a limited Secure Access Client menu, there are no secured applications shown or no way to disconnect the session – as it’s “Always On” 🙂

Citrix Secure Access Client in Machine Tunnel state

When using Machine Tunnel + User Tunnel or only User Tunnel, after logon to Windows, you will notice the following popup, when DNS resolution for suffixList cannot be resolved or resolves in non-private-IPs.

Citrix Secure Access Client Connection in Progress

…followed by the User Tunnel connection established popup. The Client Control setting in ADC AlwaysOn Profile chooses whether the user is able to disconnect the session, or not.

Citrix Secure Access Client Connection established

Configuration Hints

  • If the Auto-Login (SSO) mechanism after successful login to your Windows Account on your client isn’t working, check the permissions on C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys and the underlying files, as the Secure Access Client is using these MachineKeys for SSO.

  • Rollout or install the Secure Access Client as administrator, otherwise the inbuilt EPA-Agent isn’t able to access the client device certificate and the EPA-Check will fail.

  • The Client-Registry REG_SZ suffixList is the DNS-Suffix which you configured in your ADC Setup. This is used by the AOVPN Service to check if the Secure Access Client is able to resolve the FQDN with a private or public IP, to choose if a VPN connection has to initiate (external) or not (when connected directly internal). Set your ADS FQDN with add dns suffix contoso.local.

  • In ADC 13.0 build 71.44 and newer, the Secure Access Client for Windows supports Secure DNS update, which is disabled by default. I highly recommend to enable the setting within the Client-Registry REG_DWORD secureDNSUpdate and set it to 1 (When you set the value to 1, the plug-in tries the unsecure DNS update first. If the unsecure DNS update fails, the VPN plug-in tries the secure DNS update. To try only the secure DNS update, you can set the value to 2)

  • When using Citrix ADC native OTP as a second factor during your AOVPN login-mechanism, see Julian Mooren’s Post about a necessary traffic policy.

  • Create a dedicated traffic policy when using AOVPN / SSLVPN – otherwise the bearer authorization header get dropped and SSO to OAuth Webapps will fail.


Citrix ADC Always On is a great alternative Always On VPN solution. To note some cost hints, ICA Only mode has to be false – which means the Universal Licenses come to play. ADC Standard edition brings 500, Advanced 1000 and Premium unlimited concurrent universal licenses. Don’t forget these limitations when sizing a machine AND user tunnel Always On VPN architecture, as both tunnels consume licenses.


  1. Hallo Julian,
    ich hab Ihren Blog Eintrag in einer Lab Umgebung nachgebaut, um das für eine Kundenumgebung nachzustellen.
    Leider funktioniert es bei mir noch nicht ganz so. Maschinen Tunnel kann aufgebaut werden nur nach der Eingabe von Username, Passwort kann der User Tunnel nicht aufgebaut werden. Wenn ich das dann manuell über den Client oder die Web Oberfläche mache, funktioniert der Login. Die Konfiguration Hints in dem Artikel hab ich auch gesehen und auch die Crypto Berechtigungen geprüft. Das sollte eigentlich passen.
    Haben Sie da vllt. noch irgendeine Idee, woran es liegen kann, dass der SSO nicht funktioniert?
    Über eine Rückmeldung würd ich mich sehr freuen.
    P.S.: gerne auch per Du antworten 😉

    1. Hallo Thomas,
      das Problem musste ich auch hin und wieder feststellen und ist meist auf die Version des Secure Access Client zurückzuführen. Die aktuellsten Plugin-Versionen funktionieren zuverlässiger und switchen sauber von Maschinentunnel zum Usertunnel über.

  2. Hallo Julian,
    wir stehen vor dem Gleichen Problem mit der aktuellen Version hast Du eine Version wo du weißt da funktioniert es?

    1. Hallo Marko,

      ich konnte mit Versionen sowie erfolgreich AOVPN testen. Interessant, dass es mit erneut Probleme gibt – danke für die Info!

  3. In order to leave it to all users of the company, I didn’t understand the reason for doing this to the user as in the code below

    #Gateway vServer Settings
    add vpn alwaysONProfile AOVPN-Prof -clientControl ALLOW
    add aaa user jakobj
    bind aaa user jakobj -intranetIP

    and here also bind aaa user jakobj -policy ADV_Pol_VPN_With_SplitTunnel -priority 5

    Could you explain to me why you do this for the specific user?

    1. Hi Alex,
      jakobj is just my Testuser in my Lab (it’s matching with the sAMAccountName of my AD-User). You can use an AD-Group for specific Intranet-IP-Pool assignments and also for binding Split-Tunneling Policy. If you don’t need any filtering, you can bind the Intranet-IP-Pool and the Split-Tunnel Session policy directly to your GW vServer.

Leave a Reply

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