Wireguard failover via mwan3

I need to have multiple wireguard interfaces for resiliency. Ideally more than two wg interfaces if possible and ideally all done through luci. I've confirmed that when I only have wg0, everything works as expected. As soon as I add wg1 and/or mwan3 into the mix, then I loose all tunnel connectivity. This is a roadwarrior setup so my home wireguard server is port forwarded traffic on port 51820. I have a peer on my wireguard server for each interface in OpenWRT.

My roaming device is an RPI 5 with a USB ethernet adapter for eth1 (WAN). Idea is that it would be plugged into a hotel's network. If the hotel doesn't have a wired network port, I might need to use WifI (don't know how, probably will have to start another topic)

root@OpenWrt:~# cat /etc/config/network 

config interface 'loopback'
	option device 'lo'
	option proto 'static'
	option ipaddr '127.0.0.1'
	option netmask '255.0.0.0'

config globals 'globals'
	option ula_prefix 'fdea:6d29:2f62::/48'

config device
	option name 'br-lan'
	option type 'bridge'
	list ports 'eth0'

config interface 'lan'
	option device 'br-lan'
	option proto 'static'
	option ipaddr '192.168.2.1'
	option netmask '255.255.255.0'
	option ip6assign '60'

config interface 'wan'
	option proto 'dhcp'
	option device 'eth1'
	option peerdns '0'

config interface 'wg0'
	option proto 'wireguard'
	option private_key 'imported config from wg server'
	list addresses '10.8.0.3/24'
	list dns '172.16.0.11'
	option force_link '1'
	option metric '10'

config wireguard_wg0
	option description 'Imported peer configuration'
	option public_key 'mported config from wg server'
	option preshared_key 'L40Gh2aL2ipBaT9YnTZbzkScJM9X8suaZwoVq/1Gebg='
	list allowed_ips '0.0.0.0/0'
	list allowed_ips '::/0'
	option endpoint_host 'myhost.duckdns.org'
	option endpoint_port '51820'
	option persistent_keepalive '25'

config interface 'wg1'
	option proto 'wireguard'
	option private_key 'imported config from wg server'
	list addresses '10.8.0.4/24'
	list dns '172.16.0.11'
	option metric '20'

config wireguard_wg1
	option description 'Imported peer configuration'
	option public_key 'mported config from wg server'
	option preshared_key 'Qa2Il5UT3VtrUHacMFwxvFvsLBD1LWtceb7MANFAfHM='
	list allowed_ips '0.0.0.0/0'
	list allowed_ips '::/0'
	option endpoint_host 'myhost.duckdns.org'
	option endpoint_port '51820'


root@OpenWrt:~# cat /etc/config/firewall 

config defaults
	option input 'REJECT'
	option output 'ACCEPT'
	option forward 'REJECT'
	option synflood_protect '1'

config zone
	option name 'lan'
	list network 'lan'
	option input 'ACCEPT'
	option output 'ACCEPT'
	option forward 'ACCEPT'
	option mtu_fix '1'

config zone
	option name 'wan'
	list network 'wan'
	list network 'wan6'
	option input 'REJECT'
	option output 'ACCEPT'
	option forward 'REJECT'
	option masq '1'
	option mtu_fix '1'

config rule
	option name 'Allow-DHCP-Renew'
	option src 'wan'
	option proto 'udp'
	option dest_port '68'
	option target 'ACCEPT'
	option family 'ipv4'

config rule
	option name 'Allow-Ping'
	option src 'wan'
	option proto 'icmp'
	option icmp_type 'echo-request'
	option family 'ipv4'
	option target 'ACCEPT'

config rule
	option name 'Allow-IGMP'
	option src 'wan'
	option proto 'igmp'
	option family 'ipv4'
	option target 'ACCEPT'

config rule
	option name 'Allow-DHCPv6'
	option src 'wan'
	option proto 'udp'
	option dest_port '546'
	option family 'ipv6'
	option target 'ACCEPT'

config rule
	option name 'Allow-MLD'
	option src 'wan'
	option proto 'icmp'
	option src_ip 'fe80::/10'
	list icmp_type '130/0'
	list icmp_type '131/0'
	list icmp_type '132/0'
	list icmp_type '143/0'
	option family 'ipv6'
	option target 'ACCEPT'

config rule
	option name 'Allow-ICMPv6-Input'
	option src 'wan'
	option proto 'icmp'
	list icmp_type 'echo-request'
	list icmp_type 'echo-reply'
	list icmp_type 'destination-unreachable'
	list icmp_type 'packet-too-big'
	list icmp_type 'time-exceeded'
	list icmp_type 'bad-header'
	list icmp_type 'unknown-header-type'
	list icmp_type 'router-solicitation'
	list icmp_type 'neighbour-solicitation'
	list icmp_type 'router-advertisement'
	list icmp_type 'neighbour-advertisement'
	option limit '1000/sec'
	option family 'ipv6'
	option target 'ACCEPT'

config rule
	option name 'Allow-ICMPv6-Forward'
	option src 'wan'
	option dest '*'
	option proto 'icmp'
	list icmp_type 'echo-request'
	list icmp_type 'echo-reply'
	list icmp_type 'destination-unreachable'
	list icmp_type 'packet-too-big'
	list icmp_type 'time-exceeded'
	list icmp_type 'bad-header'
	list icmp_type 'unknown-header-type'
	option limit '1000/sec'
	option family 'ipv6'
	option target 'ACCEPT'

config rule
	option name 'Allow-IPSec-ESP'
	option src 'wan'
	option dest 'lan'
	option proto 'esp'
	option target 'ACCEPT'

config rule
	option name 'Allow-ISAKMP'
	option src 'wan'
	option dest 'lan'
	option dest_port '500'
	option proto 'udp'
	option target 'ACCEPT'

config zone
	option name 'WGZONE'
	option input 'REJECT'
	option output 'ACCEPT'
	option forward 'REJECT'
	option masq '1'
	list network 'wg0'
	list network 'wg1'

config forwarding
	option src 'lan'
	option dest 'WGZONE'




root@OpenWrt:~# cat /etc/config/mwan3 

config globals 'globals'
	option mmx_mask '0x3F00'

config interface 'wan'
	option enabled '1'
	list track_ip '1.0.0.1'
	list track_ip '1.1.1.1'
	list track_ip '208.67.222.222'
	list track_ip '208.67.220.220'
	option family 'ipv4'
	option reliability '2'

config interface 'wan6'
	option enabled '0'
	list track_ip '2606:4700:4700::1001'
	list track_ip '2606:4700:4700::1111'
	list track_ip '2620:0:ccd::2'
	list track_ip '2620:0:ccc::2'
	option family 'ipv6'
	option reliability '2'

config interface 'wanb'
	option enabled '0'
	list track_ip '1.0.0.1'
	list track_ip '1.1.1.1'
	list track_ip '208.67.222.222'
	list track_ip '208.67.220.220'
	option family 'ipv4'
	option reliability '1'

config interface 'wanb6'
	option enabled '0'
	list track_ip '2606:4700:4700::1001'
	list track_ip '2606:4700:4700::1111'
	list track_ip '2620:0:ccd::2'
	list track_ip '2620:0:ccc::2'
	option family 'ipv6'
	option reliability '1'

config member 'wan_m1_w3'
	option interface 'wan'
	option metric '1'
	option weight '3'

config member 'wan_m2_w3'
	option interface 'wan'
	option metric '2'
	option weight '3'

config member 'wanb_m1_w2'
	option interface 'wanb'
	option metric '1'
	option weight '2'

config member 'wanb_m1_w3'
	option interface 'wanb'
	option metric '1'
	option weight '3'

config member 'wanb_m2_w2'
	option interface 'wanb'
	option metric '2'
	option weight '2'

config member 'wan6_m1_w3'
	option interface 'wan6'
	option metric '1'
	option weight '3'

config member 'wan6_m2_w3'
	option interface 'wan6'
	option metric '2'
	option weight '3'

config member 'wanb6_m1_w2'
	option interface 'wanb6'
	option metric '1'
	option weight '2'

config member 'wanb6_m1_w3'
	option interface 'wanb6'
	option metric '1'
	option weight '3'

config member 'wanb6_m2_w2'
	option interface 'wanb6'
	option metric '2'
	option weight '2'

config policy 'wan_only'
	list use_member 'wan_m1_w3'
	list use_member 'wan6_m1_w3'

config policy 'wanb_only'
	list use_member 'wanb_m1_w2'
	list use_member 'wanb6_m1_w2'

config policy 'balanced'
	list use_member 'wan_m1_w3'
	list use_member 'wanb_m1_w3'
	list use_member 'wan6_m1_w3'
	list use_member 'wanb6_m1_w3'

config policy 'wan_wanb'
	list use_member 'wan_m1_w3'
	list use_member 'wanb_m2_w2'
	list use_member 'wan6_m1_w3'
	list use_member 'wanb6_m2_w2'

config policy 'wanb_wan'
	list use_member 'wan_m2_w3'
	list use_member 'wanb_m1_w2'
	list use_member 'wan6_m2_w3'
	list use_member 'wanb6_m1_w2'

config rule 'https'
	option sticky '1'
	option dest_port '443'
	option proto 'tcp'
	option use_policy 'wg0_wg1'

config rule 'default_rule_v4'
	option dest_ip '0.0.0.0/0'
	option use_policy 'wg0_wg1'
	option family 'ipv4'
	option proto 'all'
	option sticky '0'

config rule 'default_rule_v6'
	option dest_ip '::/0'
	option use_policy 'wg0_wg1'
	option family 'ipv6'
	option proto 'all'
	option sticky '0'

config interface 'wg0'
	option enabled '1'
	option initial_state 'online'
	option family 'ipv4'
	list track_ip '8.8.8.8'
	list track_ip '9.9.9.9'
	option track_method 'ping'
	option reliability '1'
	option count '1'
	option size '56'
	option max_ttl '60'
	option timeout '4'
	option interval '10'
	option failure_interval '5'
	option recovery_interval '5'
	option down '5'
	option up '5'

config interface 'wg1'
	option initial_state 'online'
	option family 'ipv4'
	list track_ip '8.8.8.8'
	list track_ip '9.9.9.9'
	option track_method 'ping'
	option reliability '1'
	option count '1'
	option size '56'
	option max_ttl '60'
	option timeout '4'
	option interval '10'
	option failure_interval '5'
	option recovery_interval '5'
	option down '5'
	option up '5'

config member 'wg0_member'
	option interface 'wg0'
	option metric '1'
	option weight '1'

config member 'wg1_member'
	option interface 'wg1'
	option metric '2'
	option weight '2'

config policy 'wg0_wg1'
	list use_member 'wg0_member'
	list use_member 'wg1_member'
	option last_resort 'unreachable'


Which device are the config files from? (I'm assuming the RPi 5).

Just as a starting point, those two are the same subnet which is probably going to cause problems. Change one of them to a different /24.

What are you actually trying to achieve here? It currently looks like you're just setting up multiple copies of basically the same tunnel.

I have made simple script for WireGuard failover, maybe that will suit your needs?

See: https://github.com/egc112/OpenWRT-egc-add-on/tree/main/wireguard-watchdog

Start with making two tunnels and check one by one if they are working, add the tunnels to the script and the script will start the first and if that is down, it will start the next tunnel

mwan3 is also a viable option

Yes this is the RPI config. I have wg-easy running at home.

Thanks for the tip. I guess that should have been a peer rather than a second interface. I've just created another wg-easy container (different port with relevant port forward rule). I can now have two wg interfaces and swap between the two by disabling one and enabling the other (I've uninstalled mwan3 for now). Not sure why it doesn't work without restarting the router though but that's not too bad.

I'm planning on having a wireguard server in more than one location so that I have options in case of a fault (power/internet outage, etc...). I've also noticed duckdns issues a few days ago that were quickly resolved, but just to be sure, I'm planning on having more than one DDNS hostnames from different providers.

Final reason is a bit of a bodge. I've noticed that if I'm disconnected for a few hours or more (e.g., moving from one location to another while roaming), the wireguard tunnel just doesn't come up. The fix is simple, just toggle the peer in wg-easy off and on again and the tunnel comes back immediately. It's not easy to replicate and test. So at the very least, I need to have more than one peer (or multiple wg-easy containers). That way, I can use an alternative tunnel in order to flip the other tunnel off and on. For that reason, I've decided against mwan3 as that would engage all tunnels (through pings) and I risk having all of them needing a restart.

@egc thanks for the script, it made me realize that I can just simply enable/disable interfaces as and when needed. I actually don't want this process automated as I need to be aware of issues rather than have some service mask the problem for me.