How to Configure Dual-WAN PCC Load Balancing for WireGuard Site-to-Site VPN Between Two MikroTik RB4011 Routers

Hello everyone,

I have two MikroTik RB4011 routers and I would like to build a site-to-site WireGuard VPN between them.

Each router has:

  • Two WAN Internet connections (WAN1 and WAN2)

  • One LAN subnet

My goal is to configure VPN load balancing using PCC so that traffic between the two sites can utilize both WAN links.

Network Topology

Site A

  • Router: MikroTik RB4011

  • LAN: 192.168.10.0/24

  • WAN1-A: Public IP #1, ex:1.1.1.1

  • WAN2-A: Public IP #2, ex: 2.2.2.2

Site B

  • Router: MikroTik RB4011

  • LAN: 192.168.20.0/24

  • WAN1-B: Public IP #1, ex: 3.3.3.3

  • WAN2-B: Public IP #2, ex: 4.4.4.4

I want to achieve the following:

  1. Establish a stable site-to-site WireGuard VPN.

  2. Use both WAN links at both sites.

  3. Load balance VPN traffic across both WAN links.

  4. Automatically fail over if one WAN link goes down.

  5. Keep the design suitable for production use.

I am considering creating two WireGuard tunnels:

Tunnel 1: Site A WAN1 ↔ Site B WAN1

Tunnel 2: Site A WAN2 ↔ Site B WAN2

Then using PCC to classify connections and route different VPN connections through different tunnels.

Could anyone share a sample configuration for this setup?

I am especially interested in the configuration of:

  • Firewall Filter Rules

  • NAT Rules

  • Mangle Rules

Any working examples or best practices would be greatly appreciated.

Thank you very much.

Hi,

what have you already tried? Anything?

well, prepare yourself to nervous breakdown
it is hard to force WG connection on multiwan to exit proper interface, and you want 2 site with multiwan ...
this is by nature of WG protocol, you could search forum for mangle/vrf WG solutions

In other words, Setting up a VPN connection between a primary WAN on one side and a Primary WAN on the other side, is the easiest path and you will get support to accomplish that.

This would enable failover, such that if the main WAN went down, the secondary WAN would pick up the VPN, and same at the other end.

THis is fairly straightforward. Anything else, gets complex fast.

A possiblity, I have done something very similar to this, but have not
tested this one. Likely needing scripting to setup next hop address for new
WAN routes if using DHCP for WAN interfaces.

Note: This assumes something near a default firewall configuration.

Define some IP Address ranges and ports.

The wireguard ports , and names.

wg1@link1 from WAN1 <-> WAN1 port = 13131 at both ends
wg2@link2 from WAN2 <-> WAN2 port = 13231 at both ends

Note: This 2 links will be force locked to the correct WAN interfaces.

** This does mean if WAN1 on Site A goes down, and WAN2 on Site B goes down,
** there will be no connectivity unless manually allowed.

IP Address ranges:

Wireguard interfaces.

192.168.100.0/30 for wg1@link1 (Site A has 192.168.100.1/30, Site B has 192.168.100.2/30)
192.168.100.8/30 for wg2@link2 (Site A has 192.168.100.9/30, Site B has 192.168.100.10/30)

Site IP Address ranges

Site A has 192.168.0.0/22
Site B has 192.168.8.0/22

Configuration...

If not already done create the 2 wireguard interfaces on each router.

wg1 for @link1
wg2 for @link2

Add these interfaces to the LAN interface list on their router.
And add IP addresses.
(will add peers later)

Site A

/interface list member
add interface=wg1 list=LAN
add interface=wg2 list=LAN

/ip address add 192.168.100.1/30 interface=wg1
/ip address add 192.168.100.9/30 interface=wg2

/ip route add blackhole disabled=no dst-address=192.168.100.0/24 gateway="" \
    distance=100 routing-table=main

Site B

/interface list member
add interface=wg1 list=LAN
add interface=wg2 list=LAN

/ip address add 192.168.100.2/30 interface=wg1
/ip address add 192.168.100.10/30 interface=wg2

/ip route add blackhole disabled=no dst-address=192.168.100.0/24 gateway="" \
    distance=100 routing-table=main

Add 2 routes on both routers.

Site A

   /ip route 
      add check-gateway=ping comment="@link1 to 3.3.3.3 prefers to use WAN1" \
      distance=5 dst-address=3.3.3.3 gateway=WAN1 routing-table=main

      add check-gateway=ping comment="@link2 to 4.4.4.4 prefers to use WAN2" \
      distance=5 dst-address=4.4.4.4 gateway=WAN2 routing-table=main

Site B

   /ip route 
      add check-gateway=ping comment="@link1 to 1.1.1.1 prefers to use WAN1" \
      distance=5 dst-address=1.1.1.1 gateway=WAN1 routing-table=main

      add check-gateway=ping comment="@link2 to 2.2.2.2 prefers to use WAN2" \
      distance=5 dst-address=2.2.2.2 gateway=WAN2 routing-table=main

Add some firewall rules, so cannot send wg1@link1 via WAN2, or wg2@link2 via WAN1
Also rules to drop wg@link1 coming in WAN2 and wg@link2 coming in WAN1

Site A

/ip firewall raw
add action=drop chain=output dst-address=3.3.3.3 out-interface=WAN2 dst-port=13131 \
    protocol=udp disabled=yes
add action=drop chain=output dst-address=4.4.4.4 out-interface=WAN1 dst-port=13231 \
    protocol=udp disabled=yes

add action=drop chain=prerouting src-address=3.3.3.3 in-interface=WAN2 dst-port=13131 \
    protocol=udp
add action=drop chain=output src-address=4.4.4.4 in-interface=WAN1 dst-port=13231 \
    protocol=udp

Site B

/ip firewall raw
add action=drop chain=output dst-address=1.1.1.1 out-interface=WAN2 dst-port=13131 \
    protocol=udp disabled=yes
add action=drop chain=output dst-address=2.2.2.2 out-interface=WAN1 dst-port=13231 \
    protocol=udp disabled=yes

add action=drop chain=prerouting src-address=1.1.1.1 in-interface=WAN2 dst-port=13131 \
    protocol=udp
add action=drop chain=output src-address=2.2.2.2 in-interface=WAN1 dst-port=13231 \
    protocol=udp

Add rules to allow the wireguard traffic
(Note: Could restrict input to a specific interface rather than in raw rules above)

Site A

/ip firewall filter
add action=accept chain=input dst-port=13131 protocol=udp
add action=accept chain=input dst-port=13231 protocol=udp

Site B

/ip firewall filter
add action=accept chain=input dst-port=13131 protocol=udp
add action=accept chain=input dst-port=13231 protocol=udp

Create the wireguard peers with appropriate allowed addresses.
(Using public key from remote wg peer)

Site A

/ip wireguard peers
add allowed-address=192.168.100.2,192.168.8.0/22 interface=wg1 name=wg1link1 \
  endpoint-address=3.3.3.3 endpoint-port=13131 public-key=SITEB-wg1-PUBLICKEY

add allowed-address=192.168.100.10,192.168.8.0/22 interface=wg2 name=wg2link2 \
  endpoint-address=4.4.4.4 endpoint-port=13231 public-key=SITEB-wg2-PUBLICKEY

Site B

/ip wireguard peers
add allowed-address=192.168.100.1,192.168.0.0/22 interface=wg1 name=wg1link1 \
  endpoint-address=1.1.1.1 endpoint-port=13131 public-key=SITEA-wg1-PUBLICKEY

add allowed-address=192.168.100.9,192.168.0.0/22 interface=wg2 name=wg2link2 \
  endpoint-address=2.2.2.2 endpoint-port=13231 public-key=SITEA-wg2-PUBLICKEY

Next add Routes to the other sites IP addresses. (Static in this case,
you could use ospf or similar)

Will use a recursive lookup via the wg interface addresses with ping.
(So if a wg connection is not working, routing will use the remaining link)

Site A

# wg1
/ip route add check-gateway=ping dst-address=192.168.8.0/22 gateway=192.168.100.2 routing-table=main

#wg2
/ip route add check-gateway=ping dst-address=192.168.8.0/22 gateway=192.168.100.10 routing-table=main

#disallow via another route.
/ip route add blackhole distance=100 dst-address=192.168.8.0/22 gateway="" routing-table=main

Site B

# wg1
/ip route add check-gateway=ping dst-address=192.168.0.0/22 gateway=192.168.100.1 routing-table=main

#wg2

/ip route add check-gateway=ping dst-address=192.168.0.0/22 gateway=192.168.100.9 routing-table=main

#disallow via another route.
/ip route add blackhole distance=100 dst-address=192.168.0.0/22 gateway="" routing-table=main

This with luck should give you 2 connected wg links, with ecmp.
You can then put pcc routing on top of this.

After some additional thought:

My previous attempt has a couple of issues.

It only allows wg1 to use SiteA WAN1 to SiteB WAN1,
wg2 to use SiteA WAN2 to SiteB WAN2.

This is to prevent possible fault where after failures for example wg1 could start Using WAN2 at both ends, and this would be stable and not fall back.

However, a better option would be: wg1 can be active so long as one end is active on its designated IP address and port. And similar for wg2.
This also allows the possibility that one end in a failure could be using a 4g modem or similar and can still get VPN connectivity.

The second issue is the dropping of incoming packets in the raw filter. This may lead to some rare incorrect behavior when the router has a lot of overloaded NAT connections. (For example, the router may well use udp 13131 for an overloaded connection to something else on its LAN)

Update
(Remove all raw firewall rules)

Site A

/ip firewall filter
add action=allow chain=input dst-port=13131 in-interface=WAN2 protocol=udp \
    src-address=3.3.3.3 comment="only allow wg1 in via WAN2 from 3.3.3.3"

add action=allow chain=input dst-port=13231 in-interface=WAN1 protocol=udp \
    src-address=4.4.4.4 comment="only allow wg2 in VIA WAN1 from 4.4.4.4"

#allow wg in on correct interface from any

add action=accept chain=input dst-port=13131 in-interface=WAN1 protocol=udp
add action=accept chain=input dst-port=13231 in-interface=WAN2 protocol=udp

Site B

/ip firewall filter
add action=allow chain=input dst-port=13131 in-interface=WAN2 protocol=udp \
    src-address=1.1.1.1 comment="only allow wg1 in via WAN2 from 1.1.1.1"

add action=allow chain=input dst-port=13231 in-interface=WAN1 protocol=udp \
    src-address=2.2.2.2 comment="only allow wg2 in VIA WAN1 from 2.2.2.2"

#allow wg in on correct interface from any

add action=accept chain=input dst-port=13131 in-interface=WAN1 protocol=udp
add action=accept chain=input dst-port=13231 in-interface=WAN2 protocol=udp