Tutorial: Step-by-Step Examples for Split Tunnel and Role-Based Access Using Domain Routing
How to use domain routing in Access Server to manage dynamic IP addresses and enforce group-based access in split tunnel VPN deployments.
Overview
This tutorial explains how to configure and validate domain routing in Access Server. Domain routing allows you to route traffic based on domain names instead of IP addresses, which is especially useful when application IPs change frequently or when access must be restricted by user or group.
This tutorial uses two practical scenarios in a split tunnel deployment:
Scenario 1: Domain routing for applications with dynamic IPs
Brandon manages IT and networking for a company that uses Access Server in split tunnel mode to provide employees with remote access to a private application.
The private application is accessed via an internal domain name (app1.example.com). Previously, Brandon had to configure access control rules using the application's IP address. Because the IP changes over time, this required frequent manual updates.
Using domain routing, Brandon can configure rules based on the application's domain name instead of its IP address, eliminating the need for ongoing rule changes.
Scenario 2: Domain routing with department-based access
The same company has two departments: Sales and Support.
The Sales team needs access to
app2.example.com.The Support team needs access to
app3.example.com.
Brandon must ensure that users can access only the applications assigned to their department. Domain routing, combined with group-based access rules, allows him to enforce this separation.
Prerequisites
Access Server 3.1.0 or newer.
Admin Web UI access.
DNS server proxy enabled globally.
One or more users or groups configured in Access Server.
Note
In our documentation, we use example IPv4 addresses and subnets reserved for documentation, such as 192.0.2.0/24, 198.51.100.0/24, and 203.0.113.0/24.
Ensure you replace them with valid IPv4 addresses and subnets for your network(s).
Step-by-Step: Scenario 1 — Domain routing for an application with a dynamic IP
In this step, you create a global domain routing rule for app1.example.com. Global rules apply to all users.
Sign in to the Admin Web UI.
Click Access Controls.
The Group and User Access Rules tab displays.
Click the Global Access Rules tab.
Under Domains, select the global routing mode:
NAT — The source IP appears as the Access Server private IP address when traffic reaches internal resources.
Specify a domain or wildcard domain in the Domains text field:
app1.example.com
Click Save and Restart.
From the Admin Web UI
Click Access Controls.
The Group and User Access Rules tab displays.
Click the Global Access Rules tab.
Confirm the global domain rule appears under Domains.
From the CLI
Connect to your console and get root privileges.
List the global ruleset:
sacli AccessControlRulesetsList
Example output:
[ { "comment": "Default ruleset for global domain rules", "id": 1, "name": "__DEFAULT___default_ruleset", "owner": "__DEFAULT__", "owner_type": "user_default", "position": 0 } ]
Note the
idvalue (in this example,1).List the rules in the ruleset:
sacli --ruleset_id '1'1 AccessControlRulesList
Replace the
ruleset_idvalue with the value from the previous example output.Example output:
[ { "action": "nat", "comment": "", "id": 1, "match_data": "app1.example.com", "match_type": "domain", "position": 0, "ruleset_id": 1, "type": "domain_routing" } ]
This confirms that the domain routing rule is configured correctly.
In this step, users connect to the VPN and generate traffic to app1.example.com, which we can verify.
Connect a VPN client to the server.
On the Access Server, start a packet capture:
tcpdump -eni any icmp
From the VPN client, run:
ping app1.example.com
Example output from the VPN client:
root@brandon:~# ping app1.example.com -c 1 PING app1.example.com (100.64.0.1) 56(84) bytes of data. 64 bytes from 100.64.0.1: icmp_seq=1 ttl=53 time=3.46 ms --- app1.example.com ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 3.456/3.456/3.456/0.000 ms
Example tcpdump output from the Access Server:
01:27:02.133777 as0t2 In ifindex 340 ethertype IPv4 (0x0800), length 104: 172.27.232.2 > 100.64.0.1: ICMP echo request, id 36543, seq 1, length 64 01:27:02.133798 eth0 Out ifindex 2 2a:db:03:a7:44:c9 ethertype IPv4 (0x0800), length 104: 64.227.6.171 > 192.0.2.1: ICMP echo request, id 36543, seq 1, length 64 01:27:02.136814 eth0 In ifindex 2 fe:00:00:00:01:01 ethertype IPv4 (0x0800), length 104: 192.0.2.1 > 64.227.6.171: ICMP echo reply, id 36543, seq 1, length 64 01:27:02.136874 as0t2 Out ifindex 340 ethertype IPv4 (0x0800), length 104: 100.64.0.1 > 172.27.232.2: ICMP echo reply, id 36543, seq 1, length 64
The VPN client results show:
The real IP of
app1.example.comis192.0.2.1.Access Server maps this to an internal IP (
100.64.0.1) from the DNS internal IP range (100.64.0.0/10by default).This mapping ensures traffic is routed through the VPN tunnel.
Note
You can view or change this internal IP range in the Admin Web UI at: VPN Server > Subnets > DNS internal IP range.
The tcpdump output confirms NAT translation between the mapped and real IPs.
In this step, you verify that firewall rules were created correctly for domain routing. The expected mappings are:
Real IP:
192.0.2.1(app1.example.com)Mapped internal IP:
100.64.0.1
Verify rules using nftables
On the Access Server, run:
nft list chain ip as_nat AS_DOMAIN_RT
Example output:
table ip as_nat { chain AS_DOMAIN_RT { ip saddr 172.27.232.2 ip daddr 100.64.0.1 meta mark set meta mark | 0x08000000 ip saddr 172.27.232.2 ip daddr 100.64.0.1 dnat to 192.0.2.1 } }This confirms that traffic from the VPN client IP is marked and DNATed from the mapped IP (
100.64.0.1) to the real application IP (192.0.2.1).
Verify rules using iptables
You can verify the same domain routing rules using either of the following commands.
Display the rules in the domain routing chain:
iptables -t nat -S AS0_DOMAIN_RT
Example output:
-N AS0_DOMAIN_RT -A AS0_DOMAIN_RT -s 172.27.232.2/32 -d 100.64.0.1/32 -j MARK --set-xmark 0x8000000/0x8000000 -A AS0_DOMAIN_RT -s 172.27.232.2/32 -d 100.64.0.1/32 -j DNAT --to-destination 192.0.2.1
Alternatively, view the rules with counters and line numbers:
iptables -t nat -L AS0_DOMAIN_RT -n -v --line-numbers
Example output:
Chain AS0_DOMAIN_RT (1 references) num pkts bytes target prot opt in out source destination 1 1 60 MARK 0 -- * * 172.27.232.2 100.64.0.1 MARK or 0x8000000 2 1 60 DNAT 0 -- * * 172.27.232.2 100.64.0.1 to:192.0.2.1
These outputs confirm that the domain routing rule for
app1.example.comhas been correctly applied at the firewall level.
Step-by-Step: Scenario 2 — Domain routing with group-based access
We'll create separate rules for the Sales and Support groups.
Sales group
Sign in to the Admin Web UI.
Click Groups and select Sales.
Click the Access Rules tab.
Click New Access Rule.
In the Address field, enter a domain:
app2.example.com
Note
Ensure you use an exact domain.
Select NAT as the destination type.
Observe that the Protocol and Port fields are disabled when a domain is entered.
Click Save rule and Restart.
Support group
Repeat the same steps for the Support group, using:
app3.example.com
From the Admin Web UI
Click Access Controls.
The Group and User Access Rules tab is displayed.
Confirm that each domain appears correctly in the Destination column for the corresponding group.
From the CLI
Connect to the console and get root privileges.
List group rulesets:
sacli AccessControlRulesetsList
Example output:
[ { "comment": "Auto-created ruleset for group Sales", "id": 2, "name": "Ruleset for Sales", "owner": "Sales", "owner_type": "group", "position": 1 }, { "comment": "Auto-created ruleset for group Support", "id": 3, "name": "Ruleset for Support", "owner": "Support", "owner_type": "group", "position": 1 } ]
Identify the ruleset IDs for the Sales and Support groups.
Using the ID values, list the rules for each ruleset:
sacli --ruleset_id '2' AccessControlRulesList sacli --ruleset_id '3' AccessControlRulesList
Example outputs:
[ { "action": "nat", "comment": "", "id": 1, "match_data": "app2.example.com", "match_type": "domain", "position": 1, "ruleset_id": 2, "type": "domain_routing" } ][ { "action": "nat", "comment": "", "id": 2, "match_data": "app3.example.com", "match_type": "domain", "position": 1, "ruleset_id": 3, "type": "domain_routing" } ]
Verify that:
Sales has a rule for
app2.example.com.Support has a rule for
app3.example.com.
Start
tcpdumpon Access Server:tcpdump -eni any icmp
From a Sales user VPN client:
ping app2.example.com
Example output:
root@sales:~# ping app2.example.com -c 1 PING app2.example.com (100.64.0.2) 56(84) bytes of data. 64 bytes from 100.64.0.2: icmp_seq=1 ttl=53 time=3.64 ms --- app2.example.com ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 3.635/3.635/3.635/0.000 ms
The real IP of
app2.example.comis192.0.2.2.Access Server maps this to an internal IP (
100.64.0.2) from the DNS internal IP range (100.64.0.0/10by default).This mapping ensures traffic is routed through the VPN tunnel.
From a Support user VPN client:
ping app3.example.com
Example output:
root@support:~# ping app3.example.com -c 1 PING app3.example.com (100.64.0.3) 56(84) bytes of data. 64 bytes from 100.64.0.3: icmp_seq=1 ttl=53 time=3.64 ms --- app3.example.com ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 3.635/3.635/3.635/0.000 ms
The real IP of
app3.example.comis192.0.2.3.Access Server maps this to an internal IP (
100.64.0.3) from the DNS internal IP range (100.64.0.0/10by default).This mapping ensures traffic is routed through the VPN tunnel.
The Access Server
tcpdumpoutputs confirm NAT translation between the real IP address and the mapped IP address.02:41:45.884195 as0t3 In ifindex 341 ethertype IPv4 (0x0800), length 104: 172.27.248.2 > 100.64.0.3: ICMP echo request, id 36990, seq 1, length 64 02:41:45.884219 eth0 Out ifindex 2 2a:db:03:a7:44:c9 ethertype IPv4 (0x0800), length 104: 64.227.6.171 > 192.0.2.3: ICMP echo request, id 36990, seq 1, length 64 02:41:45.946690 eth0 In ifindex 2 fe:00:00:00:01:01 ethertype IPv4 (0x0800), length 104: 192.0.2.3 > 64.227.6.171: ICMP echo reply, id 36990, seq 1, length 64 02:41:45.946727 as0t3 Out ifindex 341 ethertype IPv4 (0x0800), length 104: 100.64.0.3 > 172.27.248.2: ICMP echo reply, id 36990, seq 1, length 64
Each domain resolves to a mapped IP in the internal pool and is routed correctly through the VPN tunnel.
In this step, you verify that firewall rules were created correctly for domain routing and group-based access.
The expected mappings are:
Sales group
Real IP:
192.0.2.2(app2.example.com)Mapped internal IP:
100.64.0.2
Support group
Real IP:
192.0.2.3(app3.example.com)Mapped internal IP:
100.64.0.3
Verify rules using nftables
On the Access Server, run:
nft list chain ip as_nat AS_DOMAIN_RT
Example output:
table ip as_nat { chain AS_DOMAIN_RT { ip saddr 172.27.240.2 ip daddr 100.64.0.2 meta mark set meta mark | 0x08000000 ip saddr 172.27.240.2 ip daddr 100.64.0.2 dnat to 192.0.2.2 ip saddr 172.27.248.3 ip daddr 100.64.0.3 meta mark set meta mark | 0x08000000 ip saddr 172.27.248.3 ip daddr 100.64.0.3 dnat to 192.0.2.3 } }This confirms that domain routing and group-based access are functioning as expected.
Verify rules using iptables
You can verify the same domain routing rules using either of the following commands.
Display the rules in the domain routing chain:
iptables -t nat -S AS0_DOMAIN_RT
Example output:
-N AS0_DOMAIN_RT -A AS0_DOMAIN_RT -s 172.27.240.2/32 -d 100.64.0.2/32 -j MARK --set-xmark 0x8000000/0x8000000 -A AS0_DOMAIN_RT -s 172.27.240.2/32 -d 100.64.0.2/32 -j DNAT --to-destination 192.0.2.2 -A AS0_DOMAIN_RT -s 172.27.248.3/32 -d 100.64.0.3/32 -j MARK --set-xmark 0x8000000/0x8000000 -A AS0_DOMAIN_RT -s 172.27.248.3/32 -d 100.64.0.3/32 -j DNAT --to-destination 192.0.2.3
Alternatively, view the rules with counters and line numbers:
iptables -t nat -L AS0_DOMAIN_RT -n -v --line-numbers
Example output:
Chain AS0_DOMAIN_RT (1 references) num pkts bytes target prot opt in out source destination 1 1 60 MARK 0 -- * * 172.27.240.2 100.64.0.2 MARK or 0x8000000 2 1 60 DNAT 0 -- * * 172.27.240.2 100.64.0.2 to:192.0.2.2 3 1 60 MARK 0 -- * * 172.27.248.3 100.64.0.3 MARK or 0x8000000 4 1 60 DNAT 0 -- * * 172.27.248.3 100.64.0.3 to:192.0.2.3
These outputs confirm that domain routing and group-based access rules are correctly applied at the firewall level.