Beginner's question about config dual wan failover + warp

Hello everyone, first-ever post on the forum.

I’m pretty new to the MikroTik and RouterOS world, so any help would be much appreciated.

I have looked over the forum along with several hours of video tutorials to achieve my goal, which is to have a dual WAN failover + all traffic is made through Cloudflare Warp.

I am looking for some confirmation from the more experienced users that my config below is goog, or if I need to correct something.

# 2025-12-09 14:20:20 by RouterOS 7.20.5
#
# model = RBD52G-5HacD2HnD
/interface ethernet
set [ find default-name=ether1 ] name="1.ISP_A"
set [ find default-name=ether2 ] name="2.ISP_B"
set [ find default-name=ether3 ] name="3.Centarius PC"
set [ find default-name=ether4 ] name="4.TPLink AP"
set [ find default-name=ether5 ] name="5.Ethernet"
/interface wireguard
add listen-port=XX mtu=XX name=Cloudflare-WARP
/ip dhcp-server
add address-pool=dhcp interface=LAN lease-time=1d name=dhcp1
/routing table
add disabled=no fib name=To-Cloudflare
/interface bridge port
add bridge=LAN ingress-filtering=no interface="3.Centarius PC" internal-path-cost=\
    10 path-cost=10
add bridge=LAN ingress-filtering=no interface="5. Ethernet" \
    internal-path-cost=10 path-cost=10
add bridge=LAN ingress-filtering=no interface="4.TPLink" \
    internal-path-cost=10 path-cost=10
add bridge=LAN interface=*B internal-path-cost=10 path-cost=10
/ip firewall connection tracking
set udp-timeout=10s
/interface wireguard peers
add allowed-address=xxxx endpoint-address=xxxx \
    endpoint-port=2408 interface=Cloudflare-WARP name=WireGuard1 \
    persistent-keepalive=30s public-key=\
    "mykey"
/ip address
add address=xxxx/24 interface=LAN network=xxxx
add address=xxxx/12 interface=Cloudflare-WARP network=xxxx
/ip dhcp-client
add default-route-tables=main interface=1.ISP_A use-peer-dns=no
add default-route-distance=2 default-route-tables=main interface=\
    2.ISP_B use-peer-dns=no
/ip dhcp-server lease
add address=xxxx server=dhcp1
/ip dhcp-server network
add address=xxxx/24 gateway=xxxx netmask=24
/ip firewall mangle
add action=mark-routing chain=prerouting new-routing-mark=To-Cloudflare \
    passthrough=no src-address=xxxx
/ip firewall nat
add action=masquerade chain=srcnat comment="CloudFlare Internet Access" \
    out-interface=Cloudflare-WARP
add action=masquerade chain=srcnat out-interface=1.ISP_A
add action=masquerade chain=srcnat out-interface=2.ISP_B
/ip route
add comment="ISP1 - Default Route B" disabled=no distance=3 dst-address=\
    xxxx/32 gateway=xxxx routing-table=main scope=10 \
    suppress-hw-offload=no target-scope=10
add check-gateway=ping comment="ISP2 - Route B" disabled=no \
    distance=5 dst-address=xxxx gateway=PUBLIC.IP routing-table=main \
    scope=30 suppress-hw-offload=no target-scope=11
add comment="ISP2 - Default Route B" disabled=no distance=5 dst-address=\
    PUBLIC.IP gateway=xxxx routing-table=main scope=10 \
    suppress-hw-offload=no target-scope=10
add comment="ISP1 - Default Route A" disabled=no distance=2 dst-address=\
    PUBLIC.IP gateway=xxxx routing-table=main scope=10 \
    suppress-hw-offload=no target-scope=10
add check-gateway=ping comment="ISP1 - Route A" disabled=no \
    distance=2 dst-address=xxxx gateway=PUBLIC.IP routing-table=main \
    scope=30 suppress-hw-offload=no target-scope=11
add comment="ISP2 - Default Route A" disabled=no distance=4 dst-address=\
    PUBLIC.IP gateway=xxxx routing-table=main scope=10 \
    suppress-hw-offload=yes target-scope=10
add check-gateway=ping comment="ISP2 - Route A" disabled=no \
    distance=4 dst-address=xxxx gateway=PUBLIC.IP routing-table=main \
    scope=30 suppress-hw-offload=no target-scope=11
add comment="CLoudFlare Route" disabled=no distance=1 dst-address=xxxx \
    gateway=Cloudflare-WARP routing-table=To-Cloudflare scope=10 \
    suppress-hw-offload=no target-scope=10
add check-gateway=ping comment="ISP1 - Route B" disabled=no \
    distance=3 dst-address=xxxx gateway=PUBLIC.IP routing-table=main \
    scope=30 suppress-hw-offload=no target-scope=11


Many thanks in advance for any replies!

Before looking at the failover settings, you should check the base configuration.

If you rename interfaces, use the EXACT names you chose everywhere:
set [ find default-name=ether4 ] name="4.TPLink AP"
is not the same as:
add bridge=LAN ingress-filtering=no interface="4.TPLink"
internal-path-cost=10 path-cost=10
and
set [ find default-name=ether5 ] name="5.Ethernet"
is not the same as:
add bridge=LAN ingress-filtering=no interface="5. Ethernet"
internal-path-cost=10 path-cost=10

See point #21 here:

The *B here:
add bridge=LAN interface=*B internal-path-cost=10 path-cost=10
is an invalid entry, leftover from some edits.

About scopes/target scopes in routes, I personally find easier to use and remember 10/11/12, see:

1 Like

Hi @jaclaz and thank you for taking the time to look at my config!

I have corrected the names accordingly.

In regard to *B it is indeed a leftover. Do I actually need to do something?

Well it is an invalid entry, it won't do any harm, if that is the question, but the config would be cleaner if you remove it.

Often the same effect can be obtained using different methods, choosing the one (or the other) is often only a personal preference or an attempt to have as clean as possible coinfigurations.

As an example, personally, I would replace your:

/ip firewall nat
add action=masquerade chain=srcnat comment="CloudFlare Internet Access" \
    out-interface=Cloudflare-WARP
add action=masquerade chain=srcnat out-interface=1.ISP_A
add action=masquerade chain=srcnat out-interface=2.ISP_B

with:

/interface list
add name=WAN
add name=LAN
/interface list member
add interface=Cloudflare-WARP list=WAN
add interface=1.ISP_A list=WAN
add interface=2.ISP_B list=WAN
add interface=LAN list=LAN
/ip firewall nat
add action=masquerade chain=srcnat out-interface-list=WAN

this way interfaces are categorized with the common conventions used in default firewall filter rules (which BTW are completely missing in your configuration and this is NOT recommended for devices connected directly to the internet).

See Rule #8:
The twelve Rules of Mikrotik Club

Also, maybe you edited the posted export and accidentally removed it, it is missing the bridge definition in "/interface bridge".

1 Like
  1. Simply remove that line of the config, it is not needed.

  2. Also in terms of numbering the more complex you make it, the harder it is to read the config and troubleshoot. KISS! Do not use quotes for regular names of anything, keep quotes for text as in comments for example.
    So something like

/interface ethernet
set [ find default-name=ether1 ] name=eth1-ISPA
set [ find default-name=ether2 ] name=eth2-ISPB
set [ find default-name=ether3 ] name=eth3-PC"
set [ find default-name=ether4 ] name=eth4-AP
set [ find default-name=ether5 ] name=eth5-LAN"

/interface bridge port
add bridge=LAN ingress-filtering=no interface=eth3-PC
add bridge=LAN ingress-filtering=no interface=eth4-AP
add bridge=LAN ingress-filtering=no interface=eth5-LAN
  1. Since all your traffic is going out third party VPN you dont need to mangle at all, much easier to use routing rules and remove all the associated mangling rules.
/routing rule
add min-prefix=0 action=lookup-only-in-table  table=main comment="Allows local traffic"
add src-address=x.x.x.0/24  action=lookup-only-in-table table=To-Cloudflare
  1. In terms of mangling, after getting rid of what you had, add back this rule to smooth over any MTU potential issues.
/ip firewall mangle
add action=change-mss chain=forward new-mss=1380 out-interface=Cloudflare-WARP \
     protocol=tcp tcp-flags=syn tcp-mss=1381-65535
  1. In terms of the Routes as noted by jaclaz........ its a tad busy/confusing and it doesnt help that every route appears to be called default Route B! :wink: Also, although one can pretty much put the routes all in ip dhcp client (with recent versions of vers7) , you are attempting to use both also confusing. Suggestion is NOT to use or set default routes in IP DCHP client and simply use the manual routes below.
    below is a basic schema......
/ip route
{ recursive routes }
add comment="ISP1 - Primary Farthest Hop" distance=3 dst-address=0.0.0.0/0 gateway=8.8.4.4 \
     scope=10 target-scope=12  check-gateway=ping
add comment="ISP2 - Secondary Farthest Hop" distance=5 dst-address=0.0.0.0/0 gateway=9.9.9.9 \
     scope=10 target-scope=12  check-gateway=ping
-----------------------------------------------------
{ direct routes }
add comment="Primary - linked hop" distance=3  dst-address=8.8.4.4/32 gateway=ISP1-gateway-IP \
      scope=10 target-scope=11
add comment="Secondary - linked hop" distance=5  dst-address=9.9.9.9/32 gateway=ISP2-gateway-IP \
      scope=10 target-scope=11
++++++++++++++++++++++++++
{ special table }
add comment="Traffic out Primary"  dst-address=0.0.0.0/0 gateway=Cloudflare-WARP \
     routing-table=To-Cloudflare
  1. Although following the direction of given IP /12 by cloudflare, I always recommend changing to a /24 address, personal preference.

  2. What is not showing is the rest of the config, firewall rules and also DNS. Did the VPN provider give ou you a DNS to use??

@jaclaz you are right, I accidentally removed the firewall rules (any suggestions are more than welcome)

 /ip firewall address-list
add address=xxxx/24 list=Trusted_IPs
/ip firewall filter
add action=accept chain=input dst-port=xxxx protocol=udp
add action=drop chain=input comment="Drop Invalid Connections" \
    connection-state=invalid
add action=add-src-to-address-list address-list=port_scanners \
    address-list-timeout=1d chain=input comment="Detect port scanners" \
    protocol=tcp psd=21,3s,3,1
add action=drop chain=input comment="Drop port scanners" src-address-list=\
    port_scanners
add action=accept chain=input comment="Allow Established and Related" \
    connection-state=established,related
add action=accept chain=input comment="Allow Limited ICMP" limit=5,10 \
    protocol=icmp
add action=drop chain=input comment="Drop Excess ICMP" protocol=icmp
add action=accept chain=input comment="Allow WinBox from LAN" dst-port=xxxx \
    protocol=tcp src-address=xxxx
add action=accept chain=input comment="Allow SSH from LAN" dst-port=xxxx \
    protocol=tcp src-address=xxxx
add action=accept chain=input comment="Allow ICMP (Ping) from LAN" protocol=\
    icmp src-address=xxxx
add action=log chain=input comment="Log Unmatched" log-prefix=\
    "Firewall Drop: "
add action=drop chain=input comment="Drop Everything Else (Default Deny)"
/ip firewall mangle
add action=mark-routing chain=prerouting new-routing-mark=To-Cloudflare \
    passthrough=no src-address=xxxx
	
/ip service
set www disabled=yes
set ssh port=xxxx
set winbox port=xxxx

And the bridge definition

/interface bridge
add name=LAN port-cost-mode=short
add disabled=yes name=WLAN port-cost-mode=short

In regard to your recommendation on the interfaces and the use of lists, I will definitely adopt it as it is much cleaner indeed!

@anav Thank you for your comments! Much appreciated!
1. Understood
2. Understood, although the ““ are coming out from the config.rsc and not something I wrote.
3. I am having the VPN temporarily to see how it goes, and haven’t decided if I’ll keep it or disable it. I will definitely note down your recommendation and adjust the config accordingly, depending on what I choose.
4. Same as above
5. I know the comments seem confusing, but it was the easiest way for me to understand some basic things. There are not all of the Route B, and if you look closely, you’ll see

  • ISP1 - Default Route A
  • ISP1 - Default Route B
  • ISP2 - Default Route A
  • ISP2 - Default Route B
  • ISP1 - Recursive Route A
  • ISP1 - Recursive Route B
  • ISP2 - Recursive Route A
    ISP2 - Recursive Route B

The reason I have made these many Recursive routes is to cover the case that if a public DNS of the Recursive Route A is down ex. 1.1.1.1 Then check the public DNS of the Recursive Route B 8.8.8.8 to make sure ISP1 does not have Internet before switching to ISP2 (and I have applied the same logic to ISP2).

Regarding your suggestion “NOT to use or set default routes in IP DHCP client and simply use the manual routes below.” Can you elaborate on this, please?

  1. Noted and will try it

  2. Check my reply to Jaclaz above. The DNS I use is the following:

/ip dns
set allow-remote-requests=yes servers=\
    1.1.1.1,8.8.8.8,8.8.4.4,9.9.9.9,1.0.0.1,208.67.220.220

Well the routes you posted, once re-ordered, are understandable:

CLOUDFLARE	add comment="CLoudFlare Route" disabled=no distance=1 dst-address=xxxx gateway=Cloudflare-WARP routing-table=To-Cloudflare scope=10 suppress-hw-offload=no target-scope=10 

ISP1A	add comment="ISP1 - Default Route A" disabled=no distance=2 dst-address=PUBLIC.IP gateway=xxxx routing-table=main scope=10 suppress-hw-offload=no target-scope=10 
ISP1AC	add check-gateway=ping comment="ISP1 - Route A" disabled=no distance=2 dst-address=xxxx gateway=PUBLIC.IP routing-table=main scope=30 suppress-hw-offload=no target-scope=11 
	
ISP1B	add comment="ISP1 - Default Route B" disabled=no distance=3 dst-address=xxxx/32 gateway=xxxx routing-table=main scope=10 suppress-hw-offload=no target-scope=10 
ISP1BC	add check-gateway=ping comment="ISP1 - Route B" disabled=no distance=3 dst-address=xxxx gateway=PUBLIC.IP routing-table=main scope=30 suppress-hw-offload=no target-scope=11 
	

ISP2A	add comment="ISP2 - Default Route A" disabled=no distance=4 dst-address=PUBLIC.IP gateway=xxxx routing-table=main scope=10 suppress-hw-offload=yes target-scope=10 
ISP2AC	add check-gateway=ping comment="ISP2 - Route A" disabled=no distance=4 dst-address=xxxx gateway=PUBLIC.IP routing-table=main scope=30 suppress-hw-offload=no target-scope=11 
	
ISP2B	add comment="ISP2 - Default Route B" disabled=no distance=5 dst-address=PUBLIC.IP gateway=xxxx routing-table=main scope=10 suppress-hw-offload=no target-scope=10 
ISP2BC	add check-gateway=ping comment="ISP2 - Route B" disabled=no distance=5 dst-address=xxxx gateway=PUBLIC.IP routing-table=main scope=30 suppress-hw-offload=no target-scope=11 

Check scopes and target-scopes anyway. Compare with the 10/11/12 mnemonic and with the examples anav posted.

About firewall there are on the forum two main schools of thought, basically the rextenders (that believe that the default Mikrotik rules for SoHo devices are good in most cases, expecially for beginners) and the anavites (that believe that the default Mikrotik rules for Soho devices are good in most cases, expecially for beginners, BUT for the last rule in forward chain that MUST be a "drop all else" one, preceded by a set of explicit "allow" rules).

Both however deliver the same initial message:
start from the default Mikrotik rules for SoHO devices.

Well stated jaclaz, the funny bit is rextended is a real IT professional and script wizard with tons of experience but I still will never configure the firewalls without the drop all LOL.

Now I understand you wanted two canaries to check for your routes, to be doubly sure there is no connectivity for the primary and secondary.

If you think about it though.................. If the primary is down, why bother with anything recursive or fancy for the secondary wan. If its not available its not available and no traffic will occur regardless, seeing as the attempt is made on ISP2 because ISP1 is truly down.....

The only reason in my mind to continue with ISP2 with check-gateway and recursive IS IF you have services that use WAN2, regardless. For example some users had to use WAN2 all the time, or some router service had to use wan2 all the time. From what I see this is not the case and therefore WAN2 needs no special treatment.

I can present two ways to do the dual canary for this scenario. ( leaving out the special routes for this discussion)

FLAT:

/ip route
{ recursive routes }
add comment="ISP1 - Canary1"  distance=3 dst-address=0.0.0.0/0 gateway=8.8.4.4 \
     scope=10 target-scope=12  check-gateway=ping
add comment="ISP1 - Canary2" distance=4 dst-address=0.0.0.0/0 gateway=9.9.9.9 \
     scope=10 target-scope=12  check-gateway=ping
-----------------------------------------------------
{ direct routes }
add comment="Linked Hop" distance=3  dst-address=8.8.4.4/32 gateway=ISP1-gwy-IP \      
     scope=10 target-scope=11
add comment="Linked Hop" distance=4  dst-address=9.9.9.9/32 gateway=ISP2-gwy-IP \
      scope=10 target-scope=11
-------------------------------
add comment="WAN2 - Secondary" distance=5 dst-address=0.0.0.0/0 gateway=ISP2-gwy-IP

Nested (using faux address):

/ip route
{ recursive route faux address }
add dst-address=0.0.0.0/0 gateway=10.10.10.10 scope=10 target-scope=14
{ recursive canary routes }
add comment="ISP1 - Canary1"  distance=3 dst-address=10.10.10.10/32 gateway=8.8.4.4 \
     scope=10 target-scope=13  check-gateway=ping
add comment="ISP1 - Canary2" distance=4 dst-address=10.10.10.10/32 gateway=9.9.9.9 \
     scope=10 target-scope=13  check-gateway=ping
-----------------------------------------------------
{ direct routes }
add comment="Linked Hop" distance=3  dst-address=8.8.4.4/32 gateway=ISP1-gwy-IP \     
     scope=10 target-scope=12
add comment="Linked Hop" distance=4  dst-address=9.9.9.9/32 gateway=ISP2-gwy-IP \
      scope=10 target-scope=12
-------------------------------
add comment="WAN2 - Secondary" distance=5 dst-address=0.0.0.0/0 gateway=ISP2-gwy-IP

As far as firewalls rules go.........

/ip firewall address-list
add address=x.x.x.A/32 list=Trusted_IPs comment="admin device1"
add address=x.x.x.B/32 list=Trusted_IPs comment="admin device2"
add address=x.x.x.C/32 list=Trusted_IPs comment="admin device3"
etc.
/ip firewall filter
{ default rules to keep }
add action=accept chain=input connection-state=established,related
add action=drop chain=input connection-state=invalid
add action=accept chain=input protocol=icmp
(admin rules)
add action=accept chain=input comment="wg handshake" dst-port=xxxx protocol=udp
add action=accept chain=input  comment="admin access" in-interface=LAN \
    src-address-list=Trusted_IPs
add action=drop chain=input comment="Drop Everything Else
++++++++++++++++++++++++
add action=fasttrack-connection chain=forward connection-state=established,related
add action=accept chain=forward connection-state=established,related,untracked
add action=drop chain=forward connection-state=invalid
add action=accept chain=forward comment="users to wireguard"  src-address=x.x.x.0/24 \
   out-interface=Cloudflare-WARP
add action=drop chain=forward comment="drop all else"

/ip firewall mangle
add action=mark-routing chain=prerouting new-routing-mark=To-Cloudflare
passthrough=no src-address=xxxx

Thank you both for all the info! You can not imagine how much you’ve helped me and given me lots to think and read about!

@anav I have implemented the FLAT scenario and it works like a charm.

Also in the firewall filters the “add action=fasttrack-connection chain=forward connection-state=established,related” does not work for me and blocks my Internet (100% packet loss) for some reason. But I adopted the rest with some small adaptations after some reading/research I did.


add action=drop chain=forward connection-state=invalid comment="Drop Invalid Connections"
add action=accept chain=forward connection-state=established,related comment="Accept Established/Related"
add action=accept chain=forward in-interface=LAN comment="Allow New LAN traffic to Internet"
add action=log chain=forward log-prefix="Forward Drop: "
add action=drop chain=forward comment="Default Drop All Forward Traffic"

Of course, because fasstrack and mangling as you used as per your original post DO NOT get along.
Remove the mangles and replace with routing rules and it will speed up your routing experience dramatically. There is no reason to mangle and lose access to fasstrack in your scenario.

Imagine both routing rules and mangle as if they were sieves.

Mangle rules can have a very, very fine mesh.
Routing rules can only have rather coarse mesh.

If you don't need to separate finer sand from pebbles, routing rules are better/faster/easier.

I apologize in advance for the noobish question, but what if WARP/Cloudflare is down (for any reason - happened few weeks ago) and I want to disable WARP (WireGuard) completely. Can I stick with the Routing rules or is it safer to go back to Mangle rules in the absence of a VPN?

The propsed routing rules:

Do two things:

  1. make sure that local traffic remains on "main" table
  2. make sure that (non-local) traffic originating from src-address=x.x.x.0/24 ONLY goes through table "To-Cloudflare"

So, if the (only) connection now in route table "To-Cloudflare" becomes invalid/inactive, the packets originating from the src-addr in second routing rule will have no route.

Idea #1: change the second rule from action=lookup-only-in-table to action=lookup, see:

Idea #2: add in routing table "To-Cloudflare" a route via ISP1 (or 2, or both) with greater distance than the one going through gateway=Cloudflare-WARP

Thank you so much! It makes perfect sense!

That would probably be another thing.

OP asked:

and my reply was to that (and to that only).

I have no idea if (and I guess it depends on the kind of connection failure) the route in the "Cloudflare" table would become automagically invalid/inactive/unreachable, or - as the OP asked - a manual intervention would be needed, and those are anyway just ideas to test on the actual OP configuration.

1 Like

Sure. But your situation may be different than here. Should consider a separate post.

There are tools like check-gateway=ping on routes and using action=lookup (not lookup-only-in-table) which make the route inactive so if WG was down, the WG route go away and fallback to "main" routing table.

WG does have its heartbeat that "monitors" the connection. And there is /tool/netwatch with script to monitor things, including WG. On top of check-gateway for routes using WG.

So after your useful tips and guides, I have come up with this config. I would love to get feedback, especially on the firewall rules and the routing, just to make sure everything is well set up.

/interface bridge
add name=LAN port-cost-mode=short
add disabled=yes name=WLAN port-cost-mode=short

/interface ethernet
set [ find default-name=ether1 ] name=1.ISP
set [ find default-name=ether2 ] name=2.ISP
set [ find default-name=ether3 ] name=3.CentariusPC
set [ find default-name=ether4 ] name=4.TPLinkAP
set [ find default-name=ether5 ] name=5.Ethernet

/interface wireguard
add listen-port=XXXX mtu=1420 name=Cloudflare-WARP

/interface list
add name=WAN

/interface lte apn
set [ find default=yes ] ip-type=ipv4 use-network-apn=no

/ip pool
add name=dhcp ranges=XXXX-XXXX
add name=dhcp_pool1 ranges=XXX-XXXX

/ip dhcp-server
add address-pool=dhcp interface=LAN lease-time=1d name=dhcp1

/routing table
add disabled=no fib name=To-Cloudflare

/interface bridge port
add bridge=LAN ingress-filtering=no interface=3.CentariusPC internal-path-cost=10 \
    path-cost=10
add bridge=LAN ingress-filtering=no interface=5.Ethernet internal-path-cost=\
    10 path-cost=10
add bridge=WLAN ingress-filtering=no interface=*1 internal-path-cost=10 \
    path-cost=10
add bridge=WLAN ingress-filtering=no interface=*2 internal-path-cost=10 \
    path-cost=10
add bridge=LAN ingress-filtering=no interface=4.TPLinkAP internal-path-cost=\
    10 path-cost=10

/ip firewall connection tracking
set udp-timeout=10s

/ip settings
set max-neighbor-entries=8192

/ipv6 settings
set disable-ipv6=yes max-neighbor-entries=8192

/interface list member
add interface=1.ISP1 list=WAN
add interface=LAN list=*FFFFFFFF
add interface=2.ISP2 list=WAN

/interface wireguard peers
add allowed-address=0.0.0.0/0,::/0 endpoint-address=XXX \
    endpoint-port=XXXX interface=Cloudflare-WARP name=WireGuard1 \
    persistent-keepalive=30s public-key=\
    "XXXX"

/ip address
add address=XXXX/24 interface=LAN network=XXXX
add address=XXXX/24 disabled=yes interface=WLAN network=\
    XXXX
add address=XXXX/12 interface=Cloudflare-WARP network=XXXX

/ip dhcp-client
add default-route-tables=main interface=1.ISP1 use-peer-dns=no
add default-route-distance=2 default-route-tables=main interface=\
    2.ISP2 use-peer-dns=no

/ip dhcp-server
add address-pool=*5 disabled=yes interface=WLAN lease-time=1d name=dhcp2

/ip dhcp-server lease
add address=XXXX client-id=XXXX mac-address=\
    XXXX server=dhcp1
add address=XXXX client-id=XXXX mac-address=\
    XXXX server=dhcp1

/ip dhcp-server network
add address=XXXX/24 gateway=XXXX netmask=24
add address=XXXX/24 gateway=XXXX
add address=XXXX/24 gateway=XXXX

/ip dns
set allow-remote-requests=yes servers=\
    1.1.1.1,8.8.8.8,8.8.4.4,9.9.9.9,1.0.0.1,208.67.220.220

/ip firewall address-list
add address=XXXX/24 list=Trusted_IPs

/ip firewall filter
add action=accept chain=input comment="Allow Established and Related" \
    connection-state=established,related
add action=drop chain=input comment="Drop Invalid Connections" \
    connection-state=invalid
add action=accept chain=input dst-port=XXXX protocol=udp
add action=accept chain=input comment="Allow basic ping requests" protocol=\
    icmp
add action=accept chain=input comment="Accept Replies on WARP" \
    connection-state=established,related,new in-interface=Cloudflare-WARP
add action=accept chain=input comment="Accept Replies on Secondary WAN" \
    connection-state=established,related,new in-interface=2.ISP2
add action=add-src-to-address-list address-list=port_scanners \
    address-list-timeout=1d chain=input comment="Detect port scanners" \
    protocol=tcp psd=21,3s,3,1
add action=drop chain=input comment="Drop port scanners" src-address-list=\
    port_scanners
add action=accept chain=input comment="Allow WinBox from LAN" dst-port=XXXX \
    protocol=tcp src-address=XXXX
add action=accept chain=input comment="Allow SSH from LAN" dst-port=XXXX \
    protocol=tcp src-address=XXXX
add action=accept chain=input comment="Allow ICMP (Ping) from LAN" protocol=\
    icmp src-address=XXXX
add action=drop chain=input comment=\
    "Silent Drop: Excessive LAN Discovery Traffic to Router" dst-address=\
    XXXX in-interface=LAN
add action=drop chain=input comment=\
    "Silent Drop: All NEW Unsolicited LAN Traffic to Router" \
    connection-state=new in-interface=LAN
add action=log chain=input comment="Log Unmatched" log-prefix=\
    "Firewall Drop: "
add action=drop chain=input comment="Drop Everything Else (Default Deny)"
add action=fasttrack-connection chain=forward connection-state=\
    established,related hw-offload=yes
add action=accept chain=forward comment="Accept Established/Related " \
    connection-state=established,related
add action=drop chain=forward comment="Drop Invalid Connections" \
    connection-state=invalid
add action=accept chain=forward comment="Allow New LAN traffic to Internet" \
    in-interface=LAN
add action=log chain=forward log-prefix="Forward Drop: "
add action=drop chain=forward comment="Default Drop All Forward Traffic"

/ip firewall nat
add action=masquerade chain=srcnat comment="CloudFlare Internet Access" \
    out-interface=Cloudflare-WARP
add action=masquerade chain=srcnat out-interface=1.ISP1
add action=masquerade chain=srcnat out-interface=2.ISP2

/ip ipsec profile
set [ find default=yes ] dpd-interval=2m dpd-maximum-failures=5

/ip route
add comment="ISP1 - Direct Route II" disabled=no distance=3 dst-address=\
    8.8.8.8/32 gateway=XXXX routing-table=main scope=10 \
    suppress-hw-offload=no target-scope=10
add comment="ISP1 - Direct Route I" disabled=no distance=2 dst-address=\
    1.1.1.1/32 gateway=XXXX routing-table=main scope=10 \
    suppress-hw-offload=no target-scope=10
add check-gateway=ping comment="ISP1 - Recursive Route I" disabled=no \
    distance=2 dst-address=0.0.0.0/0 gateway=1.1.1.1 routing-table=main \
    scope=10 suppress-hw-offload=no target-scope=11
add comment="ISP2 - Direct Route" disabled=no distance=4 dst-address=\
    0.0.0.0/0 gateway=XXXX routing-table=main scope=10 \
    suppress-hw-offload=no target-scope=10
add comment="CLoudFlare Route" disabled=no distance=1 dst-address=0.0.0.0/0 \
    gateway=Cloudflare-WARP routing-table=To-Cloudflare scope=10 \
    suppress-hw-offload=no target-scope=10
add check-gateway=ping comment="ISP1 - Recursive Route II" disabled=no \
    distance=3 dst-address=0.0.0.0/0 gateway=8.8.8.8 routing-table=main \
    scope=10 suppress-hw-offload=no target-scope=11
add comment="ISP1 - Direct Route (WARP Disabled)" disabled=no distance=6 \
    dst-address=0.0.0.0/0 gateway=XXXX routing-table=To-Cloudflare \
    scope=10 suppress-hw-offload=no target-scope=10
add check-gateway=ping comment="ISP2 - Direct Route (WARP Disabled)" \
    disabled=no distance=7 dst-address=0.0.0.0/0 gateway=XXXX \
    routing-table=To-Cloudflare scope=10 suppress-hw-offload=no target-scope=\
    10

/ip service
set www disabled=yes
set ssh port=XXXX
set winbox port=XXXX

/routing bfd configuration
add disabled=no interfaces=all min-rx=200ms min-tx=200ms multiplier=5

/routing rule
add action=lookup-only-in-table comment="Allows local traffic" min-prefix=0 \
    table=main
add action=lookup-only-in-table src-address=XXXX/24 table=\
    To-Cloudflare


Thanks for sharing this setup. I'm still getting familiar with RouterOS, but seeing a full example like this really helps connect the dots on routing rules and WARP failover. Looking forward to trying some of these ideas on my own config.

1 Like

@Centarius
Check again Rule #6 here:

and point #21 here:

Re-check target-scope of routes, they still seem "off" to me:

A B C D E F G H
Filtered configuration single lines - Matchers in columns to the right -> dst-address gateway routing-table distance scope target-scope Target-scope should be
add check-gateway=ping comment=ISP1 - Recursive Route I disabled=no distance=2 dst-address=0.0.0.0/0 gateway=1.1.1.1 routing-table=main scope=10 suppress-hw-offload=no target-scope=11 0.0.0.0/0 1.1.1.1 main 2 10 11 12
add comment=ISP2 - Direct Route disabled=no distance=4 dst-address=0.0.0.0/0 gateway=XXXX routing-table=main scope=10 suppress-hw-offload=no target-scope=10 0.0.0.0/0 XXXX main 4 10 10 12
add comment=CLoudFlare Route disabled=no distance=1 dst-address=0.0.0.0/0 gateway=Cloudflare-WARP routing-table=To-Cloudflare scope=10 suppress-hw-offload=no target-scope=10 0.0.0.0/0 Cloudflare-WARP To-Cloudflare 1 10 10 10
add check-gateway=ping comment=ISP1 - Recursive Route II disabled=no distance=3 dst-address=0.0.0.0/0 gateway=8.8.8.8 routing-table=main scope=10 suppress-hw-offload=no target-scope=11 0.0.0.0/0 8.8.8.8 main 3 10 11 12
add comment=ISP1 - Direct Route (WARP Disabled) disabled=no distance=6 dst-address=0.0.0.0/0 gateway=XXXX routing-table=To-Cloudflare scope=10 suppress-hw-offload=no target-scope=10 0.0.0.0/0 XXXX To-Cloudflare 6 10 10 12
add check-gateway=ping comment=ISP2 - Direct Route (WARP Disabled) disabled=no distance=7 dst-address=0.0.0.0/0 gateway=XXXX routing-table=To-Cloudflare scope=10 suppress-hw-offload=no target-scope=10 0.0.0.0/0 XXXX To-Cloudflare 7 10 10 10
add comment=ISP1 - Direct Route I disabled=no distance=2 dst-address=1.1.1.1/32 gateway=XXXX routing-table=main scope=10 suppress-hw-offload=no target-scope=10 1.1.1.1/32 XXXX main 2 10 10 11
add comment=ISP1 - Direct Route II disabled=no distance=3 dst-address=8.8.8.8/32 gateway=XXXX routing-table=main scope=10 suppress-hw-offload=no target-scope=10 8.8.8.8/32 XXXX main 3 10 10 11

Recursive 10/11/12 mnemonic:
scope -> 10 for all
target-scope -> 11 for "narrow" routes
target-scope ->12 for "wide" routes