Skip to main content
RunBook Academy

VyOSXLIII · VPN RoutingVPN Routing

VPN routing basics — routing over tunnels, recursive routing, BGP/OSPF over VPN

Advanced⏱ ~22 minshow ip routeshow bgp ipv4 summaryshow ip ospf neighborshow ip ospf interfaceshow interfaces vtishow interfaces wireguardconfigurecomparecommit-confirmcommitsavepingtraceroute

What you'll learn

  • Put a route onto a WireGuard or IPsec VTI tunnel using the VyOS 1.5 configuration tree
  • Identify the two mechanisms that produce recursive routing and name the evidence for each
  • Choose between BGP, OSPF and static routing over a tunnel on the properties that actually differ
  • Configure a static fallback with an administrative distance that loses to both eBGP and iBGP

Prerequisites

Verified against VyOS 1.5.x LTS (circinus) · VyOS 1.4.x (sagitta) — legacy · FRRouting 10.x (VyOS 1.5) · Linux kernel 6.6 LTS (VyOS 1.5 base) · strongSwan 5.9.x (IPsec) · WireGuard 1.0.x (kernel module + userspace tooling) · 2026-08-19

Not yet marked complete on this device.

A tunnel that carries one LAN needs no routing protocol — a static route is shorter, more predictable and easier to reason about at 02:00. Routing over a VPN earns its complexity when there are many sites, when prefixes change often enough that editing them by hand is a source of outages, or when failover has to happen without a human.

This lesson covers how a route gets onto a tunnel on VyOS 1.5, the two distinct mechanisms that produce recursive routing (they look the same from the outside and have different fixes), how to choose between BGP and OSPF over a tunnel, and how to write a static fallback that actually behaves like one.

The tunnel interface in the routing table

Both tunnel types present a normal interface with an address, and the routing table treats them like any other. WireGuard gives you wg0; route-based IPsec gives you vti0.

set interfaces wireguard wg0 address '10.10.10.1/30'
set interfaces vti vti0 address '10.10.20.1/30'

A static route across either one points at the far end’s tunnel address:

set protocols static route 10.20.0.0/16 next-hop '10.10.10.2'
flowchart LR
  H1["Host A<br/>10.0.0.50"]
  R1["R1<br/>vti0: 10.10.20.1"]
  NET["Internet<br/>(ESP or WireGuard UDP)"]
  R2["R2<br/>vti0: 10.10.20.2"]
  H2["Host B<br/>10.20.0.50"]
  H1 --> R1
  R1 -- "10.20.0.0/16 via 10.10.20.2" --> NET
  NET --> R2
  R2 --> H2

Dynamic routing over the tunnel

The routing protocol runs over the tunnel interface as if it were a point-to-point link. On VyOS 1.5 the two protocols are configured in different places, and both moved from where older material puts them.

BGP over a tunnel

set protocols bgp system-as '65001'
set protocols bgp parameters router-id '10.10.10.1'
set protocols bgp neighbor 10.10.10.2 remote-as '65002'
set protocols bgp neighbor 10.10.10.2 update-source '10.10.10.1'
set protocols bgp neighbor 10.10.10.2 address-family ipv4-unicast
set protocols bgp address-family ipv4-unicast network '10.0.0.0/24'

Three things older course material gets wrong here. The AS number lives under system-as, not as a node name after bgp. The address family has to be activated on the neighbour as well as configured globally. And network is under address-family ipv4-unicast, not directly under bgp.

A prefix in a network statement is only advertised if it exists in the routing table. Where the local router does not otherwise have it, VyOS’s own documentation uses a blackhole static route at a distance that loses to everything real:

set protocols static route 10.0.0.0/24 blackhole distance '254'

OSPF over a tunnel

Per-interface OSPF parameters live under protocols ospf interface on 1.4 and 1.5. They are not under interfaces ethernet ethN ip ospf ... any more, which is where 1.3-era material puts them.

set protocols ospf interface vti0 area '0'
set protocols ospf interface vti0 network 'point-to-point'
set protocols ospf interface vti0 cost '10'
set protocols ospf parameters router-id '10.10.20.1'

The older set protocols ospf area 0 network 10.10.20.0/30 form still exists and enables OSPF on whatever interfaces fall inside the prefix. Prefer the interface form: it says which interface you meant, and it is where the per-interface knobs live anyway.

Recursive routing

The hazard specific to tunnelled routing: the tunnel needs the routing table to reach its own far endpoint, and the routing table can be persuaded to reach that endpoint through the tunnel. When that happens the tunnel becomes a prerequisite for itself.

The classic shape is a tunnel that comes up, works for a moment, and then black-holes — because the moment it comes up it teaches the router a route that destroys the underlay it was built on.

VyOS gives you two entirely separate ways to arrive there, and they have different fixes.

Mechanism 1 — the peer’s endpoint inside allowed-ips

set interfaces wireguard wg0 peer SITE-B address '203.0.113.2'
set interfaces wireguard wg0 peer SITE-B port '51820'
set interfaces wireguard wg0 peer SITE-B allowed-ips '10.10.10.0/30'
set interfaces wireguard wg0 peer SITE-B allowed-ips '10.20.0.0/16'

That is correct. Adding allowed-ips '203.0.113.0/24' — the block containing the peer’s own endpoint — is not, and neither is allowed-ips '0.0.0.0/0' on a router whose endpoint is reached over the same path. WireGuard’s own encapsulated packet is addressed to 203.0.113.2, so it now matches the peer’s allowed-ips and is offered back to wg0 to encrypt again.

Evidence: show ip route 203.0.113.2 resolves out of wg0, and the handshake stops completing.

Fix: take the endpoint out of allowed-ips. If the design genuinely needs a default route over the tunnel, the endpoint needs an explicit escape — a more specific static route pinning it to the WAN next hop:

set protocols static route 203.0.113.2/32 next-hop '198.51.100.254'

Mechanism 2 — IPsec installing routes for its own traffic selectors

This one has no equivalent in WireGuard and catches people who have only met mechanism 1.

By default strongSwan installs routes for the traffic selectors a peer negotiated. On a policy-based peer with narrow selectors that is convenient. On a route-based (VTI) peer the selectors default to everything, so the route it installs can cover the peer’s own public address — and the VyOS documentation states the requirement rather than suggesting it:

set vpn ipsec options disable-route-autoinstall

Evidence: a route toward the peer’s public address, or an unexpectedly broad route, appearing in show ip route at the moment the tunnel establishes and disappearing when it drops — with nothing in protocols static or any routing protocol that would have produced it.

Fix: disable-route-autoinstall, and then put the routes in deliberately, with static routes or a routing protocol.

The general rule

Whichever mechanism produced it, the invariant is the same: the route to the tunnel’s far endpoint must not resolve through the tunnel. Two ways to guarantee it, and mature designs use both:

  1. Pin the underlay. A static host route for the peer’s public address via the WAN next hop. It is more specific than anything a tunnel can teach you, so it wins on longest-prefix match regardless.
  2. Filter what the tunnel may teach. A prefix-list on the BGP session over the tunnel that rejects the underlay prefixes, so the recursive route cannot be learned in the first place. Pinning stops the symptom; filtering stops the route existing.

Static fallback, with a distance that actually loses

A common pattern: dynamic routing for the real path, plus static routes at a high administrative distance so the site does not go dark while BGP reconverges.

The distances that matter, as FRR implements them:

SourceAdministrative distance
Connected0
Static (VyOS default)1
eBGP20
OSPF110
iBGP200
set protocols static route 10.20.0.0/16 next-hop '10.10.10.2' distance '210'

The fallback is only a fallback if it survives the failure it exists for. A static route whose next hop is the far end’s tunnel address goes away with the tunnel — which is exactly when you wanted it. If the fallback is meant to survive the tunnel, its next hop has to be on a different path: a second tunnel, a different WAN, or an MPLS circuit.

BGP or OSPF over a tunnel

PropertyBGPOSPF
TransportTCP 179, unicastIP protocol 89, hellos to 224.0.0.5
Works over a tunnel as-isyesno — needs network non-broadcast plus static neighbours
Separate ASNs per siteyes, by designno — one OSPF domain
Policy controlrich: prefix-lists, route-maps, communities, AS-patharea types and metrics
Failure blast radiusa session drops, its routes withdrawan LSA change reruns SPF domain-wide
Scales withnumber of peersnumber of prefixes in one domain
Configuration costhigherlower

For two sites and one tunnel, static routes. Adding a routing protocol to carry two prefixes buys nothing and adds a thing that can be down while the tunnel is up.

For a hub with many spokes, BGP. Each spoke is a session; a spoke that misbehaves affects its own session and not the others’ SPF.

For a small number of sites already inside one OSPF domain, OSPF over the tunnel is the lower-friction choice, provided the tunnel carries its hellos — see the WireGuard note above.

For different administrative domains at each end — a partner, an acquired network, anything where the far side changes without telling you — BGP, because policy at the boundary is the point and OSPF has no equivalent.

Validation

show interfaces vti vti0
show ip route 10.20.0.0/16
show bgp ipv4 summary
show ip ospf neighbor
show ip ospf interface vti0

Read them in that order, because each one makes the next one meaningful: an interface that is down explains a session that is down, which explains a route that is missing.

Read-only / Safewhich route was selected, and by what
$ show ip route 10.20.0.0/16
Routing entry for 10.20.0.0/16
Known via "bgp", distance 20, metric 0, best
Last update 00:14:22 ago
  10.10.10.2, via vti0

Routing entry for 10.20.0.0/16
Known via "static", distance 210, metric 0
  10.10.10.2, via vti0

Illustrative output

Both entries present with the BGP one marked best is the state you want: the fallback exists and is losing. Only the static one present means the session is down. Only the BGP one present means there is no fallback, whatever the change ticket claimed.

Then prove it end to end, from a host and not from the router:

# Substitute your own values before running:
FAR_HOST=10.20.0.50

ping -c 3 "$FAR_HOST"
traceroute -n "$FAR_HOST"

A router-to-router ping uses the tunnel addresses and can succeed while every host behind the routers still fails, because the host path involves a different source address, a different route lookup on the far end, and a firewall the router-to-router test never touched.

Production failure modes

The BGP session will not establish over the tunnel

The neighbour sits in Active or Connect.

Diagnostic: show bgp ipv4 summary for the state; show ip route 10.10.10.2 to confirm the peer’s tunnel address resolves out of the tunnel interface; show interfaces vti vti0 or show interfaces wireguard wg0 for the tunnel itself.

Causes, cheapest first: the tunnel is not actually up; the peer address is not in allowed-ips on a WireGuard tunnel, so the TCP SYN is dropped after routing; the router’s own input firewall does not permit TCP 179 from the peer’s tunnel address; update-source is missing, so the session sources from the WAN address and the far end does not recognise it.

The OSPF adjacency never forms

Diagnostic: show ip ospf neighbor is empty; show ip ospf interface vti0 shows the network type and timers actually in force.

Causes, most likely first: the network type is one of the three that address their hellos to 224.0.0.5 — broadcast, point-to-point or point-to-multipoint — on an interface that is not registered as multicast-capable, so nothing arrives at the far end; non-broadcast is set but no protocols ospf neighbor entry exists, so there is nobody to unicast to; the tunnel subnet is not in allowed-ips, so even the unicast hellos are dropped; hello and dead intervals differ between the two routers, in which case the capture shows hellos arriving in both directions and being rejected.

Recursive routing black-holes the tunnel

Covered above. The distinguishing evidence is that the underlay route appears and disappears with the tunnel rather than being configured anywhere.

The tunnel flaps and the routes flap with it

Every flap withdraws and re-announces the prefixes, and every withdrawal is a brief outage for everything behind them.

Diagnostic: correlate the session drops with the tunnel’s own events in show log ipsec (IPsec) or the WireGuard handshake timestamps.

Fix the tunnel first — a routing protocol tuned to tolerate a flapping tunnel is a way of hiding the flap, not of fixing it. Then, if flaps remain: a static fallback at distance 210 so the site is not dark during reconvergence, and consideration of whether the underlay itself needs redundancy.

The MTU is wrong and only large packets notice

The routing is perfect and the tunnel drops full-size packets. Ping succeeds, transfers stall.

Fix: size the tunnel MTU for the encapsulation and clamp MSS on the tunnel interface — set interfaces vti vti0 mtu 1400 and set interfaces vti vti0 ip adjust-mss clamp-mss-to-pmtu. Part XLIII-05 covers the arithmetic.

Rollback

compare
commit-confirm 10

A routing change over a tunnel is exactly the case commit-confirm exists for: if it removes the route your own session is using, you cannot type the revert. Let the window expire instead.

If you have not committed, discard. If you have confirmed:

load /config/pre-change-TICKET.conf
commit
save

To remove just what you added:

delete protocols bgp neighbor 10.10.10.2
delete protocols ospf interface vti0
commit

Production discipline

Cross-course references

  • Part XLI-04 (XLI-VyOS-WireGuard / routing) covers allowed-ips as a routing mechanism in depth.
  • Part XLII-04 (XLII-VyOS-IPsec / route-based VTI) covers the VTI and its binding to a peer.
  • Part XLIII-02 (XLIII-VyOS-VPNRouting / BGP over VPN) and XLIII-03 (OSPF over VPN) take each protocol further.
  • Part XLIII-05 (XLIII-VyOS-VPNRouting / VPN MTU) covers the MTU arithmetic.
  • Part XXIII-02 (XXIII-VyOS-BGP / eBGP vs iBGP) covers the distances this lesson relies on.

Quiz

Knowledge check · 4 questions

  1. Q1. What makes a tunnel's routing recursive, and why does it break the tunnel rather than merely being inefficient?

  2. Q2. OSPF cannot be used over a WireGuard tunnel at all, because the interface is not multicast-capable and OSPF depends on multicast.

  3. Q3. An operator adds `set interfaces wireguard wg0 peer SITE-B allowed-ips 0.0.0.0/0` to route all branch traffic through the head office. The tunnel is up before the commit and dead a few seconds after. What happened, and how is it fixed without abandoning the full-tunnel design?

    R1's WireGuard peer SITE-B has its endpoint at 203.0.113.2, reached over the branch's WAN via 198.51.100.254. Before the change, `allowed-ips` covered only the tunnel /30 and the head office prefixes. `0.0.0.0/0` now matches every destination, including 203.0.113.2. WireGuard's own encapsulated UDP datagram is addressed to 203.0.113.2, so after the route lookup it meets the `allowed-ips` check, matches SITE-B, and is handed back to wg0 to be encrypted a second time. The handshake stops completing and the tunnel dies. Nothing in `show ip route` looks unusual, because the routing table did exactly what it was told; the second filter underneath it is where the loop closes.

  4. Q4. A branch runs iBGP over a tunnel to the data centre. The operator adds static fallback routes at distance 200 so the branch stays reachable during a flap. After the change, traffic sometimes takes the static route while the BGP session is up. Why, and what is the correct value?

    FRR gives iBGP an administrative distance of exactly 200. The static routes were configured at distance 200 as well, on advice written for eBGP, whose distance is 20 and against which 200 is a genuine fallback. With both sources at 200 the comparison is a tie, and which route is installed is decided by FRR's internal ordering rather than by the operator's intent — so the behaviour can differ between reloads and between the two routers. The fallback is not failing loudly; it is winning some of the time, which is worse, because the symptom appears only when the static next hop and the BGP next hop lead somewhere different.

Passing score: 75%. Answers are checked in this browser.