Policy-based routing on Fortigate with VPN

I’m going to give a very short and sweet summary of this article for those in a hurry that happened across this page by way of some quality Google searches.  I had two different groups of users behind one Fortigate.  I needed some of these users to reach a particular remote network across the internet with NAT.  I needed others to reach the same network through a site to site VPN without NAT.  Policy-based routing initially did not seem to work.  Turns out, it was because one of the remote networks being routed to also contained the site to site VPN destination IP.  The solution was a /32 static route for just the remote firewall’s IP, still using the tunnel device (seems weird/wrong), and then a broader policy-based route sending the appropriate traffic over the same tunnel device, with the next hop specified as being the tunnel target.  This let one group’s traffic go internet, and the other’s go VPN.

Here’s the longer version:

I encountered an odd situation recently.  I had a remote office with multiple local networks, internet access for all of them behind NAT, and a Fortigate to Fortigate site to site VPN configuration with multiple destination networks that went through the tunnel.  This is all pretty typical of companies with remote offices; remote users can access the corporate network across the VPN, but internet-bound traffic just goes out the local connection with NAT.

On the VPN config side, this is a Fortigate to Fortigate VPN, which means I was handling the VPN traffic with a single tunnel definition where the phase2 local and remote addresses were left as so the firewalls could figure it out based on policy.  If it were not Fortigate to Fortigate, you would of course have to define each local and remote network pair individually in the phase 2 settings.

With the VPN configured, networks that were supposed to go through the tunnel had relevant lines in the firewall policy permitting it, and then there were static route definitions where the ‘Device’ used to reach those external networks was set to the IPSec tunnel device.  No next hop is specified in this configuration once the tunnel device is selected.  This setup worked great, traffic from the remote users to the internet was permitted and NAT’d, traffic from the remote users to the corporate networks across the tunnel was permitted and not NAT’d.

A unique combination of events and circumstances resulted in an odd situation developing:

  • A group of staff were moved from the central office to the remote office.
  • They used web-based applications which were written to behave differently for users coming from a central office IP range.
  • Their IP range was RFC1918 space; i.e. private networks.
  • The pre-existing remote office users should continue to access the apps via public internet, or more importantly, not private network space, since that would result in the apps behaving in a way they should not see.

So, what to do.  Well, moving the central office team, moving their private network and keeping their access to the web apps as if they had not even moved was the easy part.  We’ll use the following definitions:

  • Users that are moving,
  • Web-apps hosted on public range which is on site at central office
  • Pre-existing remote office users,
  • We’ll call the IPSec tunnel defined on both Fortigates ‘Site2SiteVPN’
  • Central office Fortigate external interface (i.e., the VPN target IP) is (notice this is on the same network as the public web apps being accessed by Internet users)

The move steps:

  • Power down the users on that will be moving.
  • Delete from central office core router
  • Add static route on central office core router sending to the local Fortigate.
  • Create a VLAN for them at the remote office, create router interface, put their specific network on it.
  • VPN already exists between the two sites so no creation of a tunnel is needed
  • VPN is Fortigate to Fortigate so no adjustment or addition of IKE phase 2 networks is needed
  • Add a policy entry on remote office Fortigate saying traffic coming from the relevant interface, whether it be physical or vlan, from, is permitted to go out device Site2SiteVPN with destination with NO NAT.
  • Add a policy entry on central office Fortigate saying traffic coming in from interface Site2SiteVPN, source address, destination address, is permitted.
  • Power the migrated users back up.

Okay, at this point, I kind of wondered if things would actually work because of the fact that I needed to send traffic for across the Site2SiteVPN ‘device’ via the static route, but the remote VPN target itself was on that network at  How could you have a static route sending a particular network’s traffic through a device that would not be in an ‘up’ state if that device was not reached across the internet first instead of via the tunnel?

Well, the Fortigate perhaps anticipates this, knows what you really intended to do, or who knows what, but everything seemed to be working great.  The migrated users had their same network as before, the tunnel remained up with IPSec packets leaving via default gateway destined for, and any other traffic coming in from behind the Fortigate for the network going through the tunnel.  The migrated users were able to access the central office web ap from their private IP’s as if they had never moved since their traffic was going across the tunnel without NAT, and the remote end knew how to get the return traffic back to them through the tunnel.

All was not actually okay though.  This configuration broke access to the network for the pre-existing users at the remote office.  The reason is the static route for through the tunnel.  Those pre-existing users have no policy related to accessing the network; they had just been accessing the web apps on that network by way of their internet access policy rule stating “Remote office users on VLAN 123 are permitted to access ‘any’ via interface ‘wan1’ with NAT enabled.”  They did not have a policy allowing their traffic to cross the VPN, but the static route was forcing the traffic to only go across the VPN.  I also could not add such a policy because these users were intentionally supposed to only access the web apps via a public IP because the app behaved differently for private IP users, which would only be the central office folks.

So what to do, I knew Fortigate units supported policy based routing, but I didn’t see that option anywhere.  I discovered it needs to be enabled by way of turning on the ‘Advanced Routing’ feature.  You can do this in the GUI by editing the ‘Features’ settings on the status screen.  Okay, so that’s on, now to configure.  My initial attempt at configuring was to delete the static route using device Site2SiteVPN, and adding a policy based static route that said: “ANY protocol, coming in on VLAN 456 (the migrated users), source address, destination address, outgoing interface Site2SiteVPN, gateway address,”  I thought it was odd that it asked me for a gateway address after specifying the VPN tunnel device Site2SiteVPN, since in the traditional static route dialogue, the next hop disappears when you select a tunnel device.  I actually wasn’t sure what to put there so the VPN target IP was just a wild guess.

It didn’t work.  Traffic for all users was now going across the internet via the regular users can access the internet with NAT policy rule.  I thought policy routing was broken.  I tinkered with the next hop, could not find a value that changed anything.  How could I configure a Fortigate policy route where the next hop goes through a VPN tunnel?  I thought to myself, even though it doesn’t entirely make sense, what if I add a more specific static route just for the VPN target?  So I add a static (not policy based static) route, switch device to Site2SiteVPN, which of course takes away the next hop box, and now everything is working great.  Regular users accessing have no special policy, and no special route, so their traffic is NAT’d and leaves via the internet, the migrated users on have their traffic hit the policy route, matching firewall policy is found, their traffic goes across the tunnel without NAT.  Remote web app living in sees the original remote office users as public IP, and the migrated users as the private IP’s, everyone is happy.

So I’m still not sure why the policy-based static route was ignored until I added the more specific tunnel target static route back in, and I’m also still not sure how a Fortigate internally processes a static route directive that tells it to use a tunnel device for a destination IP, that could only be reached via the internet prior to the tunnel coming up, but it works.  Perhaps the code has some logic that says static routes using a tunnel device do not apply to IPSec packets destined for that same target that would be needed to bring the tunnel up?  That still doesn’t explain why the policy route was ignored until the static route was added.

Anyway, if someone does have this answer and wants to add comments, please do, would love a better explanation.


6 Replies to “Policy-based routing on Fortigate with VPN”

  1. MBR


    I ran into the same issue today and tried your solution. It works like a charm.
    Don’t know why policy based routing to a VPN wont work out of the box.
    Did you contacted Fortinet Support regarding this?

    Best Regards,

    • Your Mom Post author

      I didn’t contact them as I don’t have support on the small boxes, and the big boxes we have I don’t have an easy way to recreate the scenario. Hopefully will at some point though.

  2. Edson Ferreira

    Hello there.
    Googlin a bit, I came to your blog.
    I’m hitting a very similar situation.
    Traffic from subnet towards a server must go via Internet, while traffic from another should be forwarded using a IPSec VPN-tunnel.
    It’s quite funny, that I struggled in the same point, which gateway to configure in the field of policy routing.

    Looking around, I came across the blog post entry.
    In this thread, guys are discussing a similar problem, them there is a mention to the guide.
    In the guide, pay attention to the step 10.

    10) When the gateway is left as the FortiGate will check the routing table for the gateway out for that interface so there is no need to set a gateway here. If a route out for the outgoing interface is not in the routing table, the interface is considered down and the policy route is ignored.

    It is possible to specify a different Gateway from the one in the routing table for that interface. If a route out for the outgoing interface is not in the routing table, the interface is considered down and the policy route is ignored.

    In the fórum thread, the guys mentioned that, configure an IP address in each end of the tunnel and use that as Gateway (next-hop) in the policy route solved the issue.

    Thank you for your blog post, it helped me to understand the problem.

    • Fernando Quiroga

      Thanks Edson, i have a similar behavior and i fix this with your comment: “In the fórum thread, the guys mentioned that, configure an IP address in each end of the tunnel and use that as Gateway (next-hop) in the policy route solved the issue.” The weird situation was that i only have to configure it in one side of the site to site VPN (AKA HQ-Office), the other Fortigate was working from the begining.

  3. David brierley

    I had a very similar scenario and managed to get it working, to policy route via a vpn you do need the next hop.

    Just add an IP to the vpn tunnel interface , e.g. something unused – I used, it asks for a remote IP (which is usually the IP of the remote control interface where you could then run routing protocols eg. Ospf bgp between the tunnel devices).

    For the remote device add the next IP as if it was a /30 point to point , I added as the remote IP.

    Don’t actually add the IP on the remote side it doesn’t matter if it’s there or not for our purpose .

    Then on the policy route add the gateway as in this case.

    It works , I have multiple vpns to the same destination IP but routing based on the source.

    I found that if you start with a static route then you will need to clear the session states

    If your just testing run

    Diagnose sys session clear

    If your in production then filter the sessions based on IP or you’ll drop everyone’s session for a bit (bad if they are mid call for example)

    For the remote traffic In via the vpn it will still fail.

    To allow this you need to allow asymmetric routing

    Config system settings
    Set asymmetric enable

    (Or some thing similar can’t remember off top of my head)

    This will essentially allow you to bypass the reverse path lookup done on the fortigate , if it’s just one IP then you could do a policy route the other way set exit interface as the internal and then next hop as the ip of the host.

    If it’s a transit network set IP as the next router along.

  4. Bruce Stedman

    Hi folks, I’ve been struggling with this one a bit, too. FGT 6.4.x
    None of the above sub interface addressing (or variants thereof) has helped; the solution to (10) above is found here in Scenario 5 of “Technical Note: Routing behavior depending on distance and priority for static routes, and Policy Based Routes”
    • Leave the policy route with a gateway of, directed to your IKE interface/device
    • Set another _static_ route to the same dest CIDR (default, with the same distance (default 10) as your default gateway static route, with the IKE as the interface/device, but *with a larger _priority_ number* (default 0 = highest priority)
    • No sub interface addressing & routing required at all, no next hop addressing.
    #How to successfully make policy routing work with an IPsec tunnel
    #How to selectively route egress traffic across a tunnel instead of the wire
    #SNAT/DNAT/NoNAT, flow or return; (asymroute disabled)
    config router static
    edit 20
    set gateway
    set device port1
    edit 30
    set priority 50
    set device "MyIKE"
    #Traffic from to will egress across the tunnel instead of the WAN
    config router policy
    edit 10
    set src ""
    set output-device "MyIKE"


Leave a Reply

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