Dear reader, I have another installment of the quick tips series. This time the topics are FQDN-based split tunneling for IPsec with FortiClient and how to use the URL access feature of a FortiGate Web Application Firewall (WAF) profile.
Models and versions:
- FortiGate 70G on 7.6.7
- FortiClient EMS on 7.4.7
- FortiClient on 7.4.6
- Windows 11 client on 25H2
FortiClient FQDN-based split tunneling with IPsec
One of the nice things about SSL-VPN on a FortiGate is the fact that you can do FQDN-based split tunneling with relative ease by configuring it directly in a firewall policy as the destination and performing split tunneling based on the policy destination. With IPsec, this isn’t possible, because that’s not how the protocol works. The documentation even says that you cannot use FQDN objects in the split tunnel configuration.
Note:
FQDNs are not supported in split-tunnel destinations. If FQDNs have been configured in the split-tunnel address group, it cannot be applied in the (set ipv4-split-include) config of the dialup IPsec.
That won’t stop us, however.
In order to make this happen, we can use EMS’ application-based split tunneling feature while editing a tunnel. In there, you can include or exclude Cloud and Video Streaming Applications, but also Domains, and that last point is the one that is interesting, because you can use FQDNs here.
In this case, I am adding the FQDN of this blog, blog.guenay.at, to the configuration.

The VPN configuration of a FortiGate doesn’t require any special configuration for this to work, and I have configured a regular PSK VPN with split tunneling, that routes 192.168.0.0/16 into the tunnel.
FortiGate VPN configuration
config vpn ipsec phase1-interface
edit "PSK-VPN"
set type dynamic
set interface "wan1"
set ike-version 2
set keylife 28800
set peertype any
set net-device disable
set mode-cfg enable
set ipv4-dns-server1 192.168.1.169
set proposal aes256gcm-prfsha512
set dhgrp 31
set eap enable
set eap-identity send-request
set authusrgrp "VPN_USERS"
set client-resume enable
set client-resume-interval 600
set transport auto
set ipv4-start-ip 172.16.101.1
set ipv4-end-ip 172.16.101.20
set ipv4-split-include "BASE-RFC1918-192"
set psksecret ENC TaAvnptXQNmMUc/zjoy5F1CweIG8wOZUwliDjZCfvt8lr36rtJl1i95oOzgQjN22lPhP3tvZ0HOLy5XCQNtGvKO+piZ6I2wDKHVXe4Q787D5NNdrtPwonaDXZxrdyAZ5hl3r3am7zJMhWC5F5Pdz/ms5t5oew98CiSjzPUv/FHHYrxObTvi+IrxH+MW5VmUIa85ZEVlmMjY3dkVA
set dpd-retryinterval 5
next
end
config vpn ipsec phase2-interface
edit "PSK-VPN"
set phase1name "PSK-VPN"
set proposal aes256gcm
set dhgrp 31
set keepalive enable
set keylifeseconds 3600
next
end
A policy to allow the WAN-bound traffic from the VPN is, of course, also needed for our FQDN split tunneling to work.

Once the connection on FortiClient is up, we can see, in the log file of the VPN (in my case it is C:\Program Files\Fortinet\FortiClient\logs\trace\iked_ikev2_PSK-VPN7EB027B2_1.log), that split tunneling is active and per-application policies have been applied in include mode.
[2026-08-08 18:08:27.6368270 UTC+02:00] [18216:12516] [iked 801 info] Detect split tunnel with subnet 192.168.0.0 and mask 255.255.0.0
[2026-08-08 18:08:27.6368279 UTC+02:00] [18216:12516] [iked 806 info] split is 1
[2026-08-08 18:08:27.6368294 UTC+02:00] [18216:12516] [iked 365 info] Applying per-application policies
[2026-08-08 18:08:27.6368305 UTC+02:00] [18216:12516] [iked 366 info] tunnel_name = PSK-VPN
[2026-08-08 18:08:27.6373625 UTC+02:00] [18216:12516] [iked 2511 info] Non-multiconnect vpn, set dns priority to 1
[2026-08-08 18:08:27.6373679 UTC+02:00] [18216:12516] [iked 2531 info] dns_priority 1
[2026-08-08 18:08:27.6373693 UTC+02:00] [18216:12516] [iked 381 info] mode = 1, dp.priority = 1
[2026-08-08 18:08:27.6373706 UTC+02:00] [18216:12516] [iked 334 info] Applying per-application policies in include mode
For verification, here is the route table of the VPN-connected Windows client before doing anything else.
Route table before anything
IPv4 Route Table
===========================================================================
Active Routes:
Network Destination Netmask Gateway Interface Metric
0.0.0.0 0.0.0.0 192.168.100.100 192.168.100.2 25
0.0.0.0 0.0.0.0 172.16.101.2 172.16.101.1 9001
127.0.0.0 255.0.0.0 On-link 127.0.0.1 331
127.0.0.1 255.255.255.255 On-link 127.0.0.1 331
127.255.255.255 255.255.255.255 On-link 127.0.0.1 331
172.16.101.1 255.255.255.255 On-link 172.16.101.1 257
192.168.0.0 255.255.0.0 172.16.101.2 172.16.101.1 2
192.168.1.202 255.255.255.255 192.168.100.100 192.168.100.2 26
192.168.100.0 255.255.255.0 On-link 192.168.100.2 281
192.168.100.2 255.255.255.255 On-link 192.168.100.2 281
192.168.100.255 255.255.255.255 On-link 192.168.100.2 281
224.0.0.0 240.0.0.0 On-link 127.0.0.1 331
224.0.0.0 240.0.0.0 On-link 192.168.100.2 281
224.0.0.0 240.0.0.0 On-link 172.16.101.1 257
255.255.255.255 255.255.255.255 On-link 127.0.0.1 331
255.255.255.255 255.255.255.255 On-link 192.168.100.2 281
255.255.255.255 255.255.255.255 On-link 172.16.101.1 257
===========================================================================
Persistent Routes:
Network Address Netmask Gateway Address Metric
0.0.0.0 0.0.0.0 172.16.101.2 Default
===========================================================================
Once the client browses to the domain listed, the following lines appear in the log file:
[2026-08-08 18:04:47.2709530 UTC+02:00] [6764:16584] [iked 54 debug] Issue Policy: [tunnel(PSK-VPN), split_ip(46.30.213.70), split_mask(255.255.255.255), local_gwy(192.168.1.228), remote_gwy(192.168.1.202)]
[2026-08-08 18:04:47.2735528 UTC+02:00] [6764:16584] [iked 54 debug] Issue Policy: [tunnel(PSK-VPN), split_ip(46.30.213.70), split_mask(255.255.255.255), local_gwy(192.168.1.228), remote_gwy(192.168.1.202)]
The IP corresponds to the IP of blog.guenay.at.
PS C:\Users\adkevin.AD.000> ping blog.guenay.at
Pinging blog.guenay.at [46.30.213.70] with 32 bytes of data:
If we check the route table after this, we see that the IP has been added and points towards the VPN interface.
Route table after adding FQDN route
IPv4 Route Table
===========================================================================
Active Routes:
Network Destination Netmask Gateway Interface Metric
0.0.0.0 0.0.0.0 192.168.100.100 192.168.100.2 25
0.0.0.0 0.0.0.0 172.16.101.2 172.16.101.1 9001
46.30.213.70 255.255.255.255 172.16.101.2 172.16.101.1 100
127.0.0.0 255.0.0.0 On-link 127.0.0.1 331
127.0.0.1 255.255.255.255 On-link 127.0.0.1 331
127.255.255.255 255.255.255.255 On-link 127.0.0.1 331
172.16.101.1 255.255.255.255 On-link 172.16.101.1 257
192.168.0.0 255.255.0.0 172.16.101.2 172.16.101.1 2
192.168.1.202 255.255.255.255 192.168.100.100 192.168.100.2 26
192.168.100.0 255.255.255.0 On-link 192.168.100.2 281
192.168.100.2 255.255.255.255 On-link 192.168.100.2 281
192.168.100.255 255.255.255.255 On-link 192.168.100.2 281
224.0.0.0 240.0.0.0 On-link 127.0.0.1 331
224.0.0.0 240.0.0.0 On-link 192.168.100.2 281
224.0.0.0 240.0.0.0 On-link 172.16.101.1 257
255.255.255.255 255.255.255.255 On-link 127.0.0.1 331
255.255.255.255 255.255.255.255 On-link 192.168.100.2 281
255.255.255.255 255.255.255.255 On-link 172.16.101.1 257
===========================================================================
Persistent Routes:
Network Address Netmask Gateway Address Metric
0.0.0.0 0.0.0.0 172.16.101.2 Default
===========================================================================
The FortiGate also shows this traffic in the Forward Traffic log.

If we disconnect the VPN, the restoration and removal of the routes can be seen. The domain routes aren’t specifically mentioned here, however.
[2026-08-08 18:14:11.9604854 UTC+02:00] [13592:13376] [iked 1285 info] Restore route and interface setting...
[2026-08-08 18:14:11.9626475 UTC+02:00] [13592:13376] [iked 1303 info] Restore routes...
[2026-08-08 18:14:11.9627101 UTC+02:00] [13592:13376] [iked 364 info] Route del(0): Destination=192.168.1.202 Prefix=32 Nexthop=0.0.0.0 Index=3
[2026-08-08 18:14:11.9627259 UTC+02:00] [13592:13376] [iked 364 info] Route del(0): Destination=192.168.0.0 Prefix=16 Nexthop=172.16.101.2 Index=59
[2026-08-08 18:14:11.9627269 UTC+02:00] [13592:13376] [iked 1318 info] Restore interface default route option...
[2026-08-08 18:14:11.9627275 UTC+02:00] [13592:13376] [iked 1330 info] Restore interface metric...
[2026-08-08 18:14:11.9633352 UTC+02:00] [13592:13376] [iked 1345 info] Remove route and interface restore proto file(0) The operation completed successfully....
For fun, let’s see what happens if I use the Video Streaming Applications option and add YouTube and browse to just the homepage.
Adding YouTube routes and route table
[2026-08-08 19:15:05.6023606 UTC+02:00] [13044:11056] [iked 54 debug] Issue Policy: [tunnel(PSK-VPN), split_ip(142.251.150.4), split_mask(255.255.255.255), local_gwy(192.168.100.2), remote_gwy(192.168.1.202)]
[2026-08-08 19:15:05.6026407 UTC+02:00] [13044:11056] [iked 54 debug] Issue Policy: [tunnel(PSK-VPN), split_ip(142.251.151.4), split_mask(255.255.255.255), local_gwy(192.168.100.2), remote_gwy(192.168.1.202)]
[2026-08-08 19:15:05.6028006 UTC+02:00] [13044:11056] [iked 54 debug] Issue Policy: [tunnel(PSK-VPN), split_ip(142.251.157.4), split_mask(255.255.255.255), local_gwy(192.168.100.2), remote_gwy(192.168.1.202)]
[2026-08-08 19:15:05.6032742 UTC+02:00] [13044:11056] [iked 54 debug] Issue Policy: [tunnel(PSK-VPN), split_ip(142.251.156.4), split_mask(255.255.255.255), local_gwy(192.168.100.2), remote_gwy(192.168.1.202)]
[2026-08-08 19:15:05.6034173 UTC+02:00] [13044:11056] [iked 54 debug] Issue Policy: [tunnel(PSK-VPN), split_ip(142.251.152.4), split_mask(255.255.255.255), local_gwy(192.168.100.2), remote_gwy(192.168.1.202)]
[2026-08-08 19:15:05.6035045 UTC+02:00] [13044:11056] [iked 54 debug] Issue Policy: [tunnel(PSK-VPN), split_ip(142.251.155.4), split_mask(255.255.255.255), local_gwy(192.168.100.2), remote_gwy(192.168.1.202)]
[2026-08-08 19:15:05.6035589 UTC+02:00] [13044:11056] [iked 54 debug] Issue Policy: [tunnel(PSK-VPN), split_ip(142.251.154.4), split_mask(255.255.255.255), local_gwy(192.168.100.2), remote_gwy(192.168.1.202)]
[2026-08-08 19:15:05.6035967 UTC+02:00] [13044:11056] [iked 54 debug] Issue Policy: [tunnel(PSK-VPN), split_ip(142.251.153.4), split_mask(255.255.255.255), local_gwy(192.168.100.2), remote_gwy(192.168.1.202)]
[2026-08-08 19:15:05.6036401 UTC+02:00] [13044:11056] [iked 54 debug] Issue Policy: [tunnel(PSK-VPN), split_ip(142.251.150.4), split_mask(255.255.255.255), local_gwy(192.168.100.2), remote_gwy(192.168.1.202)]
[2026-08-08 19:15:05.6036984 UTC+02:00] [13044:11056] [iked 54 debug] Issue Policy: [tunnel(PSK-VPN), split_ip(142.251.151.4), split_mask(255.255.255.255), local_gwy(192.168.100.2), remote_gwy(192.168.1.202)]
[2026-08-08 19:15:05.6037528 UTC+02:00] [13044:11056] [iked 54 debug] Issue Policy: [tunnel(PSK-VPN), split_ip(142.251.157.4), split_mask(255.255.255.255), local_gwy(192.168.100.2), remote_gwy(192.168.1.202)]
[2026-08-08 19:15:05.6053667 UTC+02:00] [13044:11056] [iked 54 debug] Issue Policy: [tunnel(PSK-VPN), split_ip(142.251.156.4), split_mask(255.255.255.255), local_gwy(192.168.100.2), remote_gwy(192.168.1.202)]
[2026-08-08 19:15:05.6054232 UTC+02:00] [13044:11056] [iked 54 debug] Issue Policy: [tunnel(PSK-VPN), split_ip(142.251.152.4), split_mask(255.255.255.255), local_gwy(192.168.100.2), remote_gwy(192.168.1.202)]
[2026-08-08 19:15:05.6054551 UTC+02:00] [13044:11056] [iked 54 debug] Issue Policy: [tunnel(PSK-VPN), split_ip(142.251.155.4), split_mask(255.255.255.255), local_gwy(192.168.100.2), remote_gwy(192.168.1.202)]
[2026-08-08 19:15:05.6054903 UTC+02:00] [13044:11056] [iked 54 debug] Issue Policy: [tunnel(PSK-VPN), split_ip(142.251.154.4), split_mask(255.255.255.255), local_gwy(192.168.100.2), remote_gwy(192.168.1.202)]
[2026-08-08 19:15:05.6055338 UTC+02:00] [13044:11056] [iked 54 debug] Issue Policy: [tunnel(PSK-VPN), split_ip(142.251.153.4), split_mask(255.255.255.255), local_gwy(192.168.100.2), remote_gwy(192.168.1.202)]
[2026-08-08 19:15:05.8516774 UTC+02:00] [13044:11056] [iked 54 debug] Issue Policy: [tunnel(PSK-VPN), split_ip(142.251.127.119), split_mask(255.255.255.255), local_gwy(192.168.100.2), remote_gwy(192.168.1.202)]
[2026-08-08 19:15:05.8518532 UTC+02:00] [13044:11056] [iked 54 debug] Issue Policy: [tunnel(PSK-VPN), split_ip(142.251.110.119), split_mask(255.255.255.255), local_gwy(192.168.100.2), remote_gwy(192.168.1.202)]
[2026-08-08 19:15:05.8519067 UTC+02:00] [13044:11056] [iked 54 debug] Issue Policy: [tunnel(PSK-VPN), split_ip(142.250.154.119), split_mask(255.255.255.255), local_gwy(192.168.100.2), remote_gwy(192.168.1.202)]
[2026-08-08 19:15:05.8519922 UTC+02:00] [13044:11056] [iked 54 debug] Issue Policy: [tunnel(PSK-VPN), split_ip(142.251.20.119), split_mask(255.255.255.255), local_gwy(192.168.100.2), remote_gwy(192.168.1.202)]
[2026-08-08 19:15:05.8520852 UTC+02:00] [13044:11056] [iked 54 debug] Issue Policy: [tunnel(PSK-VPN), split_ip(192.178.183.119), split_mask(255.255.255.255), local_gwy(192.168.100.2), remote_gwy(192.168.1.202)]
[2026-08-08 19:15:05.8521251 UTC+02:00] [13044:11056] [iked 54 debug] Issue Policy: [tunnel(PSK-VPN), split_ip(142.251.13.119), split_mask(255.255.255.255), local_gwy(192.168.100.2), remote_gwy(192.168.1.202)]
[2026-08-08 19:15:05.8521565 UTC+02:00] [13044:11056] [iked 54 debug] Issue Policy: [tunnel(PSK-VPN), split_ip(142.251.14.119), split_mask(255.255.255.255), local_gwy(192.168.100.2), remote_gwy(192.168.1.202)]
[2026-08-08 19:15:05.8521861 UTC+02:00] [13044:11056] [iked 54 debug] Issue Policy: [tunnel(PSK-VPN), split_ip(142.251.127.119), split_mask(255.255.255.255), local_gwy(192.168.100.2), remote_gwy(192.168.1.202)]
[2026-08-08 19:15:05.8522174 UTC+02:00] [13044:11056] [iked 54 debug] Issue Policy: [tunnel(PSK-VPN), split_ip(142.251.110.119), split_mask(255.255.255.255), local_gwy(192.168.100.2), remote_gwy(192.168.1.202)]
[2026-08-08 19:15:05.8522468 UTC+02:00] [13044:11056] [iked 54 debug] Issue Policy: [tunnel(PSK-VPN), split_ip(142.250.154.119), split_mask(255.255.255.255), local_gwy(192.168.100.2), remote_gwy(192.168.1.202)]
[2026-08-08 19:15:05.8522766 UTC+02:00] [13044:11056] [iked 54 debug] Issue Policy: [tunnel(PSK-VPN), split_ip(142.251.20.119), split_mask(255.255.255.255), local_gwy(192.168.100.2), remote_gwy(192.168.1.202)]
[2026-08-08 19:15:05.8523062 UTC+02:00] [13044:11056] [iked 54 debug] Issue Policy: [tunnel(PSK-VPN), split_ip(192.178.183.119), split_mask(255.255.255.255), local_gwy(192.168.100.2), remote_gwy(192.168.1.202)]
[2026-08-08 19:15:05.8523485 UTC+02:00] [13044:11056] [iked 54 debug] Issue Policy: [tunnel(PSK-VPN), split_ip(142.251.13.119), split_mask(255.255.255.255), local_gwy(192.168.100.2), remote_gwy(192.168.1.202)]
[2026-08-08 19:15:05.8523786 UTC+02:00] [13044:11056] [iked 54 debug] Issue Policy: [tunnel(PSK-VPN), split_ip(142.251.14.119), split_mask(255.255.255.255), local_gwy(192.168.100.2), remote_gwy(192.168.1.202)]
IPv4 Route Table
===========================================================================
Active Routes:
Network Destination Netmask Gateway Interface Metric
0.0.0.0 0.0.0.0 192.168.100.100 192.168.100.2 25
0.0.0.0 0.0.0.0 172.16.101.2 172.16.101.1 9001
127.0.0.0 255.0.0.0 On-link 127.0.0.1 331
127.0.0.1 255.255.255.255 On-link 127.0.0.1 331
127.255.255.255 255.255.255.255 On-link 127.0.0.1 331
142.250.154.119 255.255.255.255 172.16.101.2 172.16.101.1 100
142.251.13.119 255.255.255.255 172.16.101.2 172.16.101.1 100
142.251.14.119 255.255.255.255 172.16.101.2 172.16.101.1 100
142.251.20.119 255.255.255.255 172.16.101.2 172.16.101.1 100
142.251.110.119 255.255.255.255 172.16.101.2 172.16.101.1 100
142.251.127.119 255.255.255.255 172.16.101.2 172.16.101.1 100
142.251.150.4 255.255.255.255 172.16.101.2 172.16.101.1 100
142.251.151.4 255.255.255.255 172.16.101.2 172.16.101.1 100
142.251.152.4 255.255.255.255 172.16.101.2 172.16.101.1 100
142.251.153.4 255.255.255.255 172.16.101.2 172.16.101.1 100
142.251.154.4 255.255.255.255 172.16.101.2 172.16.101.1 100
142.251.155.4 255.255.255.255 172.16.101.2 172.16.101.1 100
142.251.156.4 255.255.255.255 172.16.101.2 172.16.101.1 100
142.251.157.4 255.255.255.255 172.16.101.2 172.16.101.1 100
172.16.101.1 255.255.255.255 On-link 172.16.101.1 257
192.168.0.0 255.255.0.0 172.16.101.2 172.16.101.1 2
192.168.1.202 255.255.255.255 192.168.100.100 192.168.100.2 26
192.168.100.0 255.255.255.0 On-link 192.168.100.2 281
192.168.100.2 255.255.255.255 On-link 192.168.100.2 281
192.168.100.255 255.255.255.255 On-link 192.168.100.2 281
192.178.183.119 255.255.255.255 172.16.101.2 172.16.101.1 100
224.0.0.0 240.0.0.0 On-link 127.0.0.1 331
224.0.0.0 240.0.0.0 On-link 192.168.100.2 281
224.0.0.0 240.0.0.0 On-link 172.16.101.1 257
255.255.255.255 255.255.255.255 On-link 127.0.0.1 331
255.255.255.255 255.255.255.255 On-link 192.168.100.2 281
255.255.255.255 255.255.255.255 On-link 172.16.101.1 257
===========================================================================
Persistent Routes:
Network Address Netmask Gateway Address Metric
0.0.0.0 0.0.0.0 172.16.101.2 Default
===========================================================================
Lots of routes are being added, and this is reflected in the route table.
If you use the exclude mode in the EMS VPN configuration, you see this in the log, and the routes are added to the routing table using the regular interface with your normal default gateway. Funnily enough, you don’t see these routes being added in the log.
[2026-08-08 18:12:49.3312644 UTC+02:00] [13592:13376] [iked 801 info] Detect split tunnel with subnet 192.168.0.0 and mask 255.255.0.0
[2026-08-08 18:12:49.3312680 UTC+02:00] [13592:13376] [iked 806 info] split is 1
[2026-08-08 18:12:49.3312696 UTC+02:00] [13592:13376] [iked 365 info] Applying per-application policies
[2026-08-08 18:12:49.3312705 UTC+02:00] [13592:13376] [iked 366 info] tunnel_name = PSK-VPN
[2026-08-08 18:12:49.3327815 UTC+02:00] [13592:13376] [iked 2511 info] Non-multiconnect vpn, set dns priority to 1
[2026-08-08 18:12:49.3327865 UTC+02:00] [13592:13376] [iked 2531 info] dns_priority 1
[2026-08-08 18:12:49.3327878 UTC+02:00] [13592:13376] [iked 381 info] mode = 2, dp.priority = 1
[2026-08-08 18:12:49.3327889 UTC+02:00] [13592:13376] [iked 287 info] Applying per-application policies in exclude mode
IPv4 Route Table
===========================================================================
Active Routes:
Network Destination Netmask Gateway Interface Metric
0.0.0.0 0.0.0.0 192.168.100.100 192.168.100.2 25
0.0.0.0 0.0.0.0 172.16.101.2 172.16.101.1 9001
127.0.0.0 255.0.0.0 On-link 127.0.0.1 331
127.0.0.1 255.255.255.255 On-link 127.0.0.1 331
127.255.255.255 255.255.255.255 On-link 127.0.0.1 331
142.250.154.119 255.255.255.255 192.168.100.100 192.168.100.2 124
142.251.13.119 255.255.255.255 192.168.100.100 192.168.100.2 124
142.251.14.119 255.255.255.255 192.168.100.100 192.168.100.2 124
142.251.20.119 255.255.255.255 192.168.100.100 192.168.100.2 124
142.251.110.119 255.255.255.255 192.168.100.100 192.168.100.2 124
142.251.127.119 255.255.255.255 192.168.100.100 192.168.100.2 124
142.251.150.4 255.255.255.255 192.168.100.100 192.168.100.2 124
142.251.151.4 255.255.255.255 192.168.100.100 192.168.100.2 124
142.251.152.4 255.255.255.255 192.168.100.100 192.168.100.2 124
142.251.153.4 255.255.255.255 192.168.100.100 192.168.100.2 124
142.251.154.4 255.255.255.255 192.168.100.100 192.168.100.2 124
142.251.155.4 255.255.255.255 192.168.100.100 192.168.100.2 124
142.251.156.4 255.255.255.255 192.168.100.100 192.168.100.2 124
142.251.157.4 255.255.255.255 192.168.100.100 192.168.100.2 124
172.16.101.1 255.255.255.255 On-link 172.16.101.1 257
192.168.0.0 255.255.0.0 172.16.101.2 172.16.101.1 2
192.168.1.202 255.255.255.255 192.168.100.100 192.168.100.2 26
192.168.100.0 255.255.255.0 On-link 192.168.100.2 281
192.168.100.2 255.255.255.255 On-link 192.168.100.2 281
192.168.100.255 255.255.255.255 On-link 192.168.100.2 281
192.178.183.119 255.255.255.255 192.168.100.100 192.168.100.2 124
224.0.0.0 240.0.0.0 On-link 127.0.0.1 331
224.0.0.0 240.0.0.0 On-link 192.168.100.2 281
224.0.0.0 240.0.0.0 On-link 172.16.101.1 257
255.255.255.255 255.255.255.255 On-link 127.0.0.1 331
255.255.255.255 255.255.255.255 On-link 192.168.100.2 281
255.255.255.255 255.255.255.255 On-link 172.16.101.1 257
===========================================================================
Persistent Routes:
Network Address Netmask Gateway Address Metric
0.0.0.0 0.0.0.0 172.16.101.2 Default
===========================================================================
This method of FQDN-based split tunneling is a nice compromise when transitioning from SSL-VPN to IPsec. Don’t forget the Cloud Applications option in this, because it offers a few often-used services and acts like the other options.
FortiGate Web Application Firewall URL access
Due to a blog post about FortiClient EMS Let’s Encrypt Security that I wrote for my employer, I was told about the URL access feature that lives inside the WAF profile of a FortiGate, which I wasn’t aware of before. Outside of the CLI reference, I cannot find any documentation of this feature for a FortiGate, only for FortiWeb, but it is relatively self-explanatory. Still, let’s see how to configure it.
Note: The URL access feature is CLI-only, but you should still enable Web Application Firewall in Feature Visibility, because otherwise the option to assign the profile in a policy does not show up in the GUI. Also, you can do much the same with a web filter profile, which I do in the post above, so the WAF option is not the only method to achieve this; it just saves on another profile.
On the CLI, you can configure a basic URL access block as follows:
config waf profile
edit "WAF_URL-ACCESS"
config url-access
edit 1
set address "ubuntu-ws-1.ad.labdomain.com"
set action block
set log enable
config access-pattern
edit 1
set srcaddr "all"
set pattern ".*/login.html$"
set regex enable
next
end
next
end
next
end
Let’s go through it.
The address option determines the backend host that is being protected, and it is an actual address object. I have tested it with the types ipmask and fqdn, and both worked here, assuming your DNS resolution is correct for the FQDN option.
action has the block option, which does exactly that, bypass, which allows the connection and skips all other WAF scanning, and permit, which allows the connection and continues with WAF scanning.
log is for logging; who would have thought.
In the access-pattern entry itself, we can set the srcaddr option, which determines to which source address this should apply, so we can target only specific addresses. Again, this is an actual address object.
Enabling regex does that, and because I prefer regex-matching over everything else, I have it enabled. Disabling it probably does a simple match on the URL, but I didn’t test this because if regex is available, I will use only that.
The actual regex pattern is used in the pattern option. In my case, I am checking for every URL path that ends in /login.html.
That’s it on how to configure the feature.
Note that there is no implicit deny rule here, so if you don’t have an entry for a pattern, it is allowed. Entries are matched top down, so keep that in mind.
Assign the WAF profile in a policy, and if you perform deep inspection, either with an SSL/SSH profile or a virtual server, you can also control access in HTTPS traffic.

If I test the URL https://ubuntu-ws-1.ad.labdomain.com/login.html on my client, I get the block, as expected, and I see this in my FortiGate Web Application Firewall log.


Browsing to any other URL, like https://ubuntu-ws-1.ad.labdomain.com/index.html or just https://ubuntu-ws-1.ad.labdomain.com, does not lead to a block, because I never explicitly mentioned this in my WAF profile and I also don’t have a catch-all entry.
If you ever need to debug this feature, then you need to know that the WAF feature uses the wad process, and the category http is the important one.
diagnose wad debug enable category http
diagnose wad debug enable level info
diagnose debug enable
In the debugs, you can see the request coming in and the URL access being matched.
FortiGate Web Application Firewall debug
[I][p:1758][s:11239][r:33554552] wad_dump_http_request :3134 hreq=0x7f9df0d8e0 Received request from client: 192.168.100.2:56531
GET /login.html HTTP/1.1
Host: ubuntu-ws-1.ad.labdomain.com
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
sec-ch-ua: "Not=A?Brand";v="99", "Microsoft Edge";v="151", "Chromium";v="151"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.0.0 Safari/537.36 Edg/151.0.0.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: en-GB,en;q=0.9,en-US;q=0.8
Cookie: session=expiry=1786211939675194
[I][p:1758][s:11239][r:33554552] wad_http_parse_host :2019 host=[28]ubuntu-ws-1.ad.labdomain.com
[I][p:1758][s:11239][r:33554552] wad_http_str_canonicalize :2621 enc=0 path=/login.html len=11 changes=0
[I][p:1758][s:11239][r:33554552] wad_http_req_detect_special :14589 captive_portal detected: false, preflight=(null)
[I][p:1758][s:11239][r:33554552] wad_http_req_domain_front_chk :9751 chk uri host res=pass (is_abs=0 http_encap=1 connect=0): ubuntu-ws-1.ad.labdomain.com
[I][p:1758][s:11239][r:33554552] wad_http_waf_access_control :1242
[I][p:1758][s:11239][r:33554552] wad_http_waf_access_control :1269 WAF matched URL access action=1
[I][p:1758][s:11239][r:33554552] __wad_http_build_replmsg_resp :933 Generating replacement message. repmsg_id 77
[I][p:1758][s:11239][r:33554552] wad_dump_fwd_http_resp :3155 hreq=0x7f9df0d8e0 Forward response from Internal:
HTTP/1.1 403 Forbidden
Connection: close
Content-Type: text/html
Cache-Control: no-cache
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Content-Security-Policy: frame-ancestors 'self'
Content-Length: 35039
If you want a configuration that allows a specific URL path and blocks all others, you can configure it like this:
config waf profile
edit "WAF_URL-ACCESS"
config url-access
edit 1
set address "ubuntu-ws-1.ad.labdomain.com"
set log enable
config access-pattern
edit 1
set srcaddr "all"
set pattern ".*/login.html$"
set regex enable
next
end
next
edit 2
set address "ubuntu-ws-1.ad.labdomain.com"
set action block
set log enable
config access-pattern
edit 1
set srcaddr "all"
set pattern ".*"
set regex enable
next
end
next
end
next
end
And that’s that feature explained.
Short and sweet and done
The configuration for both things in this quick tips installment isn’t anything to write home about, as it should be for this series, but I haven’t seen much on either of these things, so hopefully this helps at least you, dear reader.
