← Start of tutorial

WIUNIX ACADEMY

WireGuard hub and spoke with filtered BGP and FRRouting

Page 3 of 6. Review the earlier steps and prerequisites before continuing.

YOUR SYSTEM. YOUR STEPS.

Where are you working?

Choose your OS and version. The prerequisites, commands and troubleshooting follow your environment.

Ubuntu 26.04 LTSReviewed against official documentation ·

USE YOUR OWN VALUES

Configure this tutorial

Set the example values for your environment; related explanations and copy panels update together. Never enter passwords, private keys or tokens. Values stay in this tab and are not sent to the server or share links. Check actual DNS, certificates and network policy before running commands.

Different IP addresses, domains or ports? Open the settings below, change the values and select “Apply to tutorial”, then copy the updated commands.

Set values for my environment19 editable values
10

LET’S BUILD

Constrain BGP before starting FRR

Using the existing firewall manager, allow hub UDP51871 and UDP51872 from the actual spoke egress addresses (or a deliberate roaming policy). Allow replies on spokes. Allow TCP179 only between 10.254.1.1↔10.254.1.2 on wg-ac-a and 10.254.2.1↔10.254.2.2 on wg-ac-b, never on public interfaces. Restrict forwarding to 10.71.10.0/24↔10.72.20.0/24 and required test/application services, with established replies and ICMP fragmentation-needed for PMTUD. Preserve management and do not NAT the LANs. An accept in another nftables base chain cannot override a later drop. The additive guard below only blocks public BGP; it does not open required traffic or replace the existing firewall. Run before FRR on each VM; a table name collision means stop.

bash

Dedicated fresh lab gateways; Bash

sudo nft list table inet academy_bgp 2>/dev/null && exit 1
sudo nft -f - <<'NFT'
table inet academy_bgp {
 chain input {
  type filter hook input priority -10; policy accept;
  tcp dport 179 iifname != { "wg-ac-a", "wg-ac-b" } counter drop
 }
}
NFT
sudo nft list table inet academy_bgp
How do I know it worked?

Public BGP is blocked; separately reviewed existing firewall rules permit only the described peers, UDP and selected LAN traffic.

11

LET’S BUILD

Bring up transport and check route ownership

Use the hub lines on the hub and the matching spoke line on each spoke. No remote LAN route should appear yet. A recent handshake proves cryptographic exchange, not BGP or forwarding. MTU1380 is a conservative starting example for a1500-byte underlay, not universal; smaller paths require a smaller reviewed MTU on both ends. Strict rp_filter can discard valid asymmetric traffic. On these fresh lab gateways enable forwarding first, then loose reverse-path checks; a production policy needs a separate review. Snapshot values were retained in the lab root.

bash

Dedicated fresh lab gateways; Bash

sudo sysctl -w net.ipv4.ip_forward=1
sudo sysctl -w net.ipv4.conf.all.rp_filter=2 net.ipv4.conf.default.rp_filter=2
case "$ROLE" in
 h) sudo wg-quick up 'wg-ac-a'; sudo wg-quick up 'wg-ac-b' ;;
 a) sudo wg-quick up 'wg-ac-a' ;;
 b) sudo wg-quick up 'wg-ac-b' ;;
 *) exit 1 ;;
esac
sudo wg show
ip route show proto kernel
ip route show proto bgp
How do I know it worked?

Matching interfaces are UP with connected /30 routes; traffic triggers a recent handshake. No remote LAN route exists until BGP installs it.

12

LET’S BUILD

Open the integrated routing configuration

On each fresh VM paste only its matching file below. The initial package configuration is backed up. Keep zebra enabled and set bgpd=yes in the distribution daemon file; enable no other protocol. No redistribute connected, default-originate, route reflector, broad permit or no-policy bypass belongs in this design. Prefix lists match exact CIDRs; implicit deny rejects everything else. maximum-prefix is a secondary limit on accepted prefixes, not a substitute for filters or a guarantee against control-plane overload.

bash

Dedicated fresh lab gateways; Bash

sudo nano /etc/frr/daemons /etc/frr/frr.conf
How do I know it worked?

The saved integrated file matches this node’s role; zebra and bgpd are enabled and no unrelated routing protocol is enabled.

13

LET’S BUILD

File: hub routing

Use this file only on hub. The LAN network must have an exact connected route on its owner; do not manufacture reachability with a blackhole route.

text · /etc/frr/frr.conf

Dedicated fresh lab gateways; Bash

frr defaults traditional
service integrated-vtysh-config
hostname academy-hub
ip prefix-list FROM-A seq 10 permit 10.71.10.0/24
ip prefix-list FROM-B seq 10 permit 10.72.20.0/24
router bgp 65000
 bgp router-id 10.254.1.1
 bgp ebgp-requires-policy
 no bgp default ipv4-unicast
 neighbor 10.254.1.2 remote-as 65010
 neighbor 10.254.1.2 update-source 10.254.1.1
 neighbor 10.254.1.2 timers 3 9
 neighbor 10.254.2.2 remote-as 65020
 neighbor 10.254.2.2 update-source 10.254.2.1
 neighbor 10.254.2.2 timers 3 9
 address-family ipv4 unicast
  neighbor 10.254.1.2 activate
  neighbor 10.254.1.2 prefix-list FROM-A in
  neighbor 10.254.1.2 prefix-list FROM-B out
  neighbor 10.254.1.2 maximum-prefix 1
  neighbor 10.254.1.2 next-hop-self
  neighbor 10.254.2.2 activate
  neighbor 10.254.2.2 prefix-list FROM-B in
  neighbor 10.254.2.2 prefix-list FROM-A out
  neighbor 10.254.2.2 maximum-prefix 1
  neighbor 10.254.2.2 next-hop-self
 exit-address-family
How do I know it worked?

Both neighbors have exact inbound and outbound prefix lists, maximum-prefix1 and next-hop-self; hub advertises no local/default network.

14

LET’S BUILD

File: spoke A routing

Use this file only on spoke A. The LAN network must have an exact connected route on its owner; do not manufacture reachability with a blackhole route.

text · /etc/frr/frr.conf

Dedicated fresh lab gateways; Bash

frr defaults traditional
service integrated-vtysh-config
hostname academy-a
ip prefix-list OWN seq 10 permit 10.71.10.0/24
ip prefix-list REMOTE seq 10 permit 10.72.20.0/24
router bgp 65010
 bgp router-id 10.254.1.2
 bgp ebgp-requires-policy
 bgp network import-check
 no bgp default ipv4-unicast
 neighbor 10.254.1.1 remote-as 65000
 neighbor 10.254.1.1 update-source 10.254.1.2
 neighbor 10.254.1.1 timers 3 9
 address-family ipv4 unicast
  network 10.71.10.0/24
  neighbor 10.254.1.1 activate
  neighbor 10.254.1.1 prefix-list REMOTE in
  neighbor 10.254.1.1 prefix-list OWN out
  neighbor 10.254.1.1 maximum-prefix 1
 exit-address-family
How do I know it worked?

A advertises exactly 10.71.10.0/24 and accepts exactly 10.72.20.0/24 from AS65000, with network import-check enabled.

15

LET’S BUILD

File: spoke B routing

Use this file only on spoke B. The LAN network must have an exact connected route on its owner; do not manufacture reachability with a blackhole route.

text · /etc/frr/frr.conf

Dedicated fresh lab gateways; Bash

frr defaults traditional
service integrated-vtysh-config
hostname academy-b
ip prefix-list OWN seq 10 permit 10.72.20.0/24
ip prefix-list REMOTE seq 10 permit 10.71.10.0/24
router bgp 65020
 bgp router-id 10.254.2.2
 bgp ebgp-requires-policy
 bgp network import-check
 no bgp default ipv4-unicast
 neighbor 10.254.2.1 remote-as 65000
 neighbor 10.254.2.1 update-source 10.254.2.2
 neighbor 10.254.2.1 timers 3 9
 address-family ipv4 unicast
  network 10.72.20.0/24
  neighbor 10.254.2.1 activate
  neighbor 10.254.2.1 prefix-list REMOTE in
  neighbor 10.254.2.1 prefix-list OWN out
  neighbor 10.254.2.1 maximum-prefix 1
 exit-address-family
How do I know it worked?

B advertises exactly 10.72.20.0/24 and accepts exactly 10.71.10.0/24 from AS65000, with network import-check enabled.

Explore all tutorials ↗