Local Internet Breakout in Practice: SD-WAN Zones, Rules, and a Multi-VRF Guest Wi-Fi Walkthrough

Every post in this blog’s SD-WAN material has, at some point, talked about where traffic goes: to a hub, across an ADVPN shortcut, out through a centrally-steered breakout. What’s been missing is the layer underneath all of that — the actual mechanism a FortiGate uses to decide, session by session, “this one goes out the WAN, that one goes out the door.” That mechanism is SD-WAN zones, members, and rules, and the most common reason to reach for it deliberately is local internet breakout (LIB): letting a session exit to the internet from the branch itself, rather than crossing an overlay to be broken out somewhere else.

This post does two things. First, it builds up the zones/members/rules model properly — the part that From DSCP to Deep Packet Inspection and the Hub Placement series both lean on without spelling out. Second, it walks through the scenario that makes LIB interesting rather than trivial: a branch with both corporate and guest Wi-Fi, where guest traffic needs to break out locally, in its own VRF, without ever touching the corporate tunnel — tying directly into MP-BGP and VRFs on FortiGate SD-WAN and the DPI problems explored in Why DPI Breaks Guest Wi-Fi.

The building blocks: zones, members, and rules

It’s easy to use these three terms loosely. FortiOS doesn’t:

  • SD-WAN members are the actual interfaces — physical, VLAN, IPsec tunnel, whatever — that SD-WAN can steer traffic across. Each one gets a seq-num and, usually, a cost.
  • SD-WAN zones are named groups of members. The default zone is virtual-wan-link, but any non-trivial design creates more: an underlay zone for raw internet circuits, an overlay zone for the IPsec tunnels to the hub, and — this is the piece this post cares about — an isolated zone for a breakout path that should never carry anything except one specific kind of traffic.
  • SD-WAN rules (technically service entries under config system sdwan) are the policy layer: “for traffic matching this (source, destination, application, internet-service, or DSCP marking), prefer these members, selected by this strategy (lowest-cost SLA, best-quality SLA, manual priority, ECMP, and so on), falling back to these if the SLA isn’t met.”

The mental model that makes this click: a zone is a pool of candidate exits, and a rule is the question “which exit, for this traffic, right now?” Performance SLA health-checks (the mechanism covered at length in the SD-WAN Resilience series) continuously answer “is this member still good enough?” — and a rule’s strategy decides what to do with that answer.

config system sdwan
    config zone
        edit "underlay"
        next
        edit "overlay"
        next
        edit "guest-breakout"
        next
    end
    config members
        edit 1
            set interface "wan1"
            set zone "underlay"
        next
        edit 2
            set interface "wan2"
            set zone "underlay"
        next
        edit 3
            set interface "ipsec-hub1"
            set zone "overlay"
        next
        edit 4
            set interface "ipsec-hub2"
            set zone "overlay"
        next
        edit 5
            set interface "wan1"
            set zone "guest-breakout"
        next
    end
end

Notice member 5: wan1 appears in two zones — underlay and guest-breakout. That’s deliberate and it’s the crux of how LIB coexists with everything else on the same physical circuit, which the next section unpacks.

What “local internet breakout” actually means, mechanically

Strip away the design-philosophy framing (the Hub Placement series covers why the industry moved this direction) and LIB is three things happening together for a given session:

  1. An SD-WAN rule selects a member in the underlay/local-breakout zone, not the overlay zone, for traffic matching some criteria — typically an internet-service match (Microsoft 365, a SaaS app, “any internet-bound traffic from this VRF”) rather than a destination-subnet match, since the whole point is that the destination isn’t a known internal prefix.
  2. A policy route or the SD-WAN rule itself sends the session out a local WAN interface instead of into a tunnel — which means it never gets encapsulated, never crosses the overlay, and never lands on the hub’s firewall policy.
  3. Firewall policy and source NAT exist locally, on the branch FortiGate, for that egress interface — because a session that used to be NAT’d at the hub now needs its own NAT (and its own logging, and its own security profile application, if you’re not willing to skip inspection on local breakout — which, per the DPI-and-guest-Wi-Fi post, you usually shouldn’t be).

That third point is the one people forget, and it’s the one that turns “just add an SD-WAN rule” into “actually finish the design.” A session breaking out locally needs everything the hub used to provide for it — NAT, policy, logging, inspection — re-provisioned on the spoke. That’s a real cost (CPU, licensing for security profiles at the edge, log volume now originating from hundreds of branches instead of a handful of hubs) and it’s the actual trade being made when you choose LIB over backhaul. The DSCP-to-DPI post frames this as the point where “always backhaul and inspect centrally” stopped being affordable at scale; LIB is the architectural answer, and this is what it costs to implement properly.

Why this gets interesting: Guest Wi-Fi in its own VRF

Here’s the scenario that makes all three of those points concrete. A branch has corporate Wi-Fi and guest Wi-Fi. The requirements, which should sound familiar to anyone who’s actually built one of these:

  • Guest traffic must be fully isolated from corporate — no route between the two, ever, even by misconfiguration. Route Leaking Between VRFs on FortiGate exists precisely because “no route between two VRFs” is a stronger and more auditable guarantee than “a firewall policy that denies it,” and guest isolation is the textbook case for wanting that guarantee.
  • Guest internet traffic should break out locally — there’s no reason to consume hub capacity, hub licensing, or overlay bandwidth carrying a guest’s video stream across an IPsec tunnel to a DC three hundred miles away just to hand it back to the internet on the other side.
  • Corporate traffic should continue to use the overlay exactly as designed — SLA-steered, centrally inspected where policy requires it, reaching internal apps through the hub.

The clean way to build this — and the way that makes the isolation guarantee structural rather than procedural — is to put guest traffic in its own VRF, give that VRF its own SD-WAN zone, and let that zone’s only member be a path to the local internet circuit that the corporate VRF’s overlay traffic also egresses through (encapsulated, in the corporate case; raw, in the guest case).

                        wan1 (underlay circuit)
                              |
              +---------------+---------------+
              |                               |
      [ zone: underlay ]              [ zone: guest-breakout ]
      VRF 0 (corporate)                VRF 1 (guest)
      -> IPsec to hub (overlay)        -> raw NAT'd egress, local
      -> SLA-steered, inspected        -> local FW policy + UTM
              |                               |
        [ overlay tunnels ]             [ internet, direct ]
              |
          HUB (DC / cloud)

Same physical circuit, two VRFs, two SD-WAN zones, two completely independent decision paths — and because they’re different VRFs, there is no routing table in which a guest packet and a corporate prefix can ever coexist. That’s the same principle the MP-BGP and VRFs post builds the corporate-side overlay design around, applied here in the opposite direction: instead of using VRFs to segment which overlay traffic uses, you’re using them to segment overlay vs. no overlay at all.

Building it: VRF and interface assignment

Assume internal-corp and internal-guest are the SSID-mapped interfaces (or VLAN sub-interfaces off a trunk to the AP controller — the access-layer detail doesn’t change anything below it):

config system interface
    edit "internal-corp"
        set vdom "root"
        set vrf 0
    next
    edit "internal-guest"
        set vdom "root"
        set vrf 1
    next
end

VRF 0 is corporate (the FortiGate default, and where the overlay tunnels and the rest of this blog’s BGP-on-loopback design already live). VRF 1 is guest, and — critically — it has no BGP session, no static route, and no policy route into VRF 0. That absence is the isolation guarantee. There’s nothing to misconfigure into a leak, because there’s no mechanism that could carry one.

Building it: the guest breakout zone and rule

The guest VRF needs its own exit. Reusing wan1 as a member of a dedicated zone — as shown in the zones config earlier — gives it one without requiring a second physical circuit:

config system sdwan
    config members
        edit 5
            set interface "wan1"
            set zone "guest-breakout"
            set source "<guest subnet>"
            set vrf 1
        next
    end
    config service
        edit 10
            set name "guest-local-breakout"
            set mode sla
            set src "<guest subnet>"
            set dst "all"
            set internet-service-custom-group "all-internet"
            set zone "guest-breakout"
            set priority-members 5
        next
    end
end

The set vrf 1 on the member is what makes a single wan1 interface usable as both a corporate underlay member (VRF 0, used as a probe/fallback path and as one leg of the overlay’s underlay reachability) and a guest local-breakout member (VRF 1, raw egress) without the two ever being reachable from each other’s routing context. The SD-WAN rule then does nothing more exotic than “guest subnet, any destination, any internet service → use the guest-breakout zone.” There’s no SLA comparison against overlay members to make, because the overlay isn’t a candidate — it’s not in the zone the rule is allowed to choose from.

Building it: NAT, policy, and inspection — the part that’s easy to skip

This is the step that the phrase “just enable local breakout” glosses over, and it’s where a design either holds up under audit or doesn’t:

config firewall policy
    edit 100
        set name "guest-local-internet"
        set srcintf "internal-guest"
        set dstintf "wan1"
        set srcaddr "guest-subnet"
        set dstaddr "all"
        set action accept
        set schedule "always"
        set service "ALL"
        set utm-status enable
        set ssl-ssh-profile "certificate-inspection"
        set av-profile "guest-av"
        set webfilter-profile "guest-web"
        set application-list "guest-appctrl"
        set logtraffic all
        set nat enable
    next
end

Three things in that policy are doing real work:

  • set nat enable — the session needs source NAT here, on the branch, because it’s not crossing an overlay to be NAT’d at the hub anymore. Skip this and guest devices simply can’t reach the internet (or, worse on some topologies, they leak a private source address onto a public circuit).
  • utm-status enable plus a guest-specific profile set — this is the direct payoff of reading Why DPI Breaks Guest Wi-Fi before building this policy rather than after: a generic corporate UTM profile, applied unmodified to guest traffic, is exactly the mismatch that post diagnoses (certificate-pinned apps breaking under SSL inspection, QoE cratering under full-depth scanning of high-volume streaming). Guest gets its own profile set, tuned for “mostly unmanaged devices doing mostly streaming and browsing,” not a copy-paste of the corporate one.
  • logtraffic all — this traffic no longer generates a single, centrally-visible log entry at the hub. If you want visibility into what guest devices are doing (and most compliance regimes require some), this branch-local policy is now the only place that visibility originates. Multiply by every branch doing LIB and you’ve reproduced, in miniature, the FAZ ingest-volume conversation from Hub Placement Part 1 — except now it’s branches generating the volume, not spokes-via-hub. Plan FortiAnalyzer (or syslog) capacity accordingly before this rolls out fleet-wide, not after the first capacity alert fires.

DNS: the detail that breaks LIB silently

One more thing worth naming because it causes a specific, maddening failure mode: if guest DNS queries still resolve via a corporate-side resolver reachable only through the (now-bypassed) overlay, guest devices will get DNS answers optimized for a path they’re no longer taking — or no answers at all, if VRF isolation (correctly) prevents the query from reaching that resolver in the first place. The fix is unglamorous but mandatory: give the guest VRF its own DNS path, either a local FortiGate DNS proxy/forwarder bound to VRF 1, or a public resolver reached over the same local-breakout zone. Get this wrong and the symptom looks like “guest Wi-Fi is randomly slow” — which sends people chasing SLA and SD-WAN rule configuration for hours before anyone thinks to run nslookup from a guest device.

Verifying it: reading the rule’s decision back

Once it’s built, the question becomes “is it actually doing what I think it’s doing?” Two commands answer that directly:

diagnose sys sdwan service

This dumps each configured rule, which zone and members it’s currently allowed to choose from, which member it’s actively selected, and — for mode sla rules — which SLA targets are currently met or missed. For the guest rule, you’re looking for confirmation that its candidate set is guest-breakout and only guest-breakout; if overlay members show up as candidates, the zone or VRF assignment has a gap somewhere.

diagnose sys sdwan health-check status <name>

Run against any performance-SLA probe relevant to the corporate side, this is the same tool the Resilience series uses to validate SLA-steering decisions — useful here mainly as a negative check: the guest rule shouldn’t reference a health-check at all (there’s nothing to compare against in a single-member zone), so if one shows up attached to it, that’s a copy-paste artifact from a corporate rule template worth removing.

And the most direct sanity check of all — confirm there is no path between the VRFs:

get router info routing-table vrf 1

If a corporate prefix shows up in VRF 1’s table (or vice versa), stop immediately. That’s not a tuning issue; it’s the isolation guarantee failing, and it means either a route-leak configuration crept in somewhere (Route Leaking Between VRFs catalogues exactly how that happens, usually by accident, usually via a “helpful” static route or an over-broad redistribution statement) or VRF assignment on an interface or SD-WAN member is wrong.

Where this fits in the bigger picture

Local internet breakout is the mechanism that makes the architectural shift described across the Hub Placement series actually work at the branch — it’s the thing that lets “the DC stops being the default route” turn from a slide in a design deck into traffic actually leaving from where it’s generated. Guest Wi-Fi is the cleanest possible scenario to learn it on, because the isolation requirement forces you to get the VRF/zone/rule relationship exactly right — there’s no “close enough” when the failure mode is a guest device reaching a corporate subnet. Once that relationship is solid here, applying the same zones-and-rules thinking to the harder case — partial local breakout for specific SaaS applications from the corporate VRF, sitting alongside SLA-steered overlay traffic on the same circuit — is a matter of degree, not of kind.