Tailscale exit node not working with mwan3 on OpenWrt 25.12.4 (GL.iNet Flint 2 MT-6000)

Hi, I'm relatively new to OpenWrt so please bear with me if I'm missing something obvious.

Hardware:

  • GL.iNet Flint 2 (MT-6000)

Setup:

  • OpenWrt 25.12.4 (r32933-4ccb782af7)
  • Tailscale v1.96.4-2
  • mwan3 with two WAN interfaces: PPPoE (primary) and LTE (backup/failover)
  • Tailscale configured as exit node with advertised routes: 0.0.0.0/0, ::/0, 192.168.1.0/24

Problem: The Tailscale exit node stopped working after upgrading from OpenWrt 25.12.2 to 25.12.4. Clients can connect to the Tailscale network and reach subnet routes, but when using the router as an exit node they can connect but have no internet access.

Root cause (as far as I can tell): Tailscale detects the presence of /etc/config/mwan3 through an internal function called checkOpenWRTUsingMWAN3 and moves its ip rule entries to priority 1300-1400 instead of the default 5200-5300. In this mode, Tailscale does not install the default routes (0.0.0.0/0 and ::/0) into its routing table 52, apparently expecting mwan3 to handle them — but mwan3 doesn't do this for Tailscale traffic.

The result is that routing table 52 is missing the default routes and traffic from clients using the router as an exit node never reaches the internet.

Confirmed by testing: When I rename /etc/config/mwan3 and restart Tailscale, the default routes appear correctly in table 52 and the exit node works perfectly. Restoring the file breaks it again.

ip rule list:

0:      from all lookup local
1001:   from all iif pppoe-wan lookup 1
1002:   from all iif eth2 lookup 2
1310:   from all fwmark 0x80000/0xff0000 lookup main
1330:   from all fwmark 0x80000/0xff0000 lookup default
1350:   from all fwmark 0x80000/0xff0000 unreachable
1370:   from all lookup 52
2001:   from all fwmark 0x100/0x3f00 lookup 1
2002:   from all fwmark 0x200/0x3f00 lookup 2
2061:   from all fwmark 0x3d00/0x3f00 blackhole
2062:   from all fwmark 0x3e00/0x3f00 unreachable
3001:   from all fwmark 0x100/0x3f00 unreachable
3002:   from all fwmark 0x200/0x3f00 unreachable
32766:  from all lookup main
32767:  from all lookup default

ip route show table 52 (with mwan3 active — broken):

10.10.70.0/24 dev tailscale0
100.68.141.57 dev tailscale0
100.80.220.61 dev tailscale0
[...other Tailscale peers...]
# NOTE: no default routes (0.0.0.0/0 or ::/0)

Additional notes:

  • On OpenWrt 25.12.2 this was working, apparently because I had manually modified /etc/init.d/tailscale at some point to make it wait for mwan3 to finish configuring before starting. That file is not included in OpenWrt backups and gets overwritten by sysupgrade, so the fix was lost during the upgrade.
  • mwan3 itself works correctly for WAN failover
  • Tailscale subnet routing (non-exit-node) works fine
  • mwan3 also shows iptables/nftables compatibility errors on restart (table 'mangle' is incompatible, use 'nft' tool) but this seems to be a separate known issue

Related issue on Tailscale GitHub: https://github.com/tailscale/tailscale/issues/12667

Question: Is there a supported or recommended way to make mwan3 and Tailscale exit node work together on OpenWrt 25.12.4? Any help would be greatly appreciated.

Sux.
At least it did when I made a travel router with a pi2 zero.

Is this a travel router?
If not; there are better options.

Thanks for the reply! No, this is not a travel router, it's my main home router.

My use case requires Tailscale specifically because I need to interconnect several subnets, some of which are shared nodes that I don't manage myself, so I don't really have a better alternative for what I need to do.

The exit node feature would actually just be a nice bonus. I already have Tailscale running on a HomeAssistant instance with exit node enabled, so I can fall back to that in an emergency.

That said, I'd really like to solve this conflict between mwan3 and Tailscale, because if I simply remove /etc/config/mwan3 everything works perfectly. So the issue is clearly the interaction between the two, not Tailscale itself.

Any suggestions on how to make them coexist would be much appreciated!

This says:
"I cannot choose, on my own, what AP to connect to; so, I need Tailscale to choose for me"?

Is that right?

Not exactly, I think there may been some misunderstanding about my use case.

I need to interconnect multiple subnets across different physical locations simultaneously. Some of those nodes are not managed by me (they belong to other people), so I cannot install alternative software on them. Tailscale is already there and that's what I have to work with.

Access points have absolutely nothing to do with my question, I have no idea where that came from.

The actual question is very simple: how do I prevent mwan3 from taking priority over Tailscale's routing tables? That's all I need to know.
Whether you like Tailscale or not, or think there are better alternatives, is not relevant to me.
I have no choice about it.

I'm weird.

Well, that is not inviting...
But my leash is still 6 hours...

Hmmm, read the Tailscale Wiki...

It owns the router.
But, I assure you: Tailscale is problematic, if not set up as a, dedicated, travel router.
It is a pita, when used correctly...
you are using it 'off-label'.

If someone else thinks they can CLI it into submission, I would, wildly, watch them walk you through it.
That, I want to see.

Help them:
Dump all your configs.

Let's see this mess.

As I understand, a compatibility issue between mwan3 and tailscale. I am not wondering about it, as both meddle around with routing and nftables. Especially, as mwan3 for nftables is quite new.

I would try following experiments, first, to make sure, both functionalities are started sequentially.

a) disable tailscale, and start it from rc.local, explicitly. After a sleep 180, to be on safe side. Does it work ? Or what is wrong ? routing, nftables ?

b) In case, a) did not work, just do the same for mwan3.

If both do not work, you still have the last option, NOT to use the meddling around with nftables and routing, provided by the packages, but to do it yourself. Good learning expirience :slight_smile: I had to do it already myself, when setting up a transparent socks5 proxy on the router (TPROXY), both for local and routed traffic.

In case, for a) or b) you manually figure out, whats missing/.wrong, you might patch this using cmds in rc.local

Thanks for the suggestions. We already did some debugging and the root cause is quite clear.

When Tailscale starts, it detects the presence of /etc/config/mwan3 through an internal function called checkOpenWRTUsingMWAN3. When mwan3 is detected, Tailscale deliberately changes its behavior: it moves its ip rule entries to priority 1300-1400 (instead of the normal 5200-5300) and stops installing default routes (0.0.0.0/0 and ::/0) into its routing table 52.

This is confirmed directly in the binary:

mwan3 on openWRT detected, switching policy base priority to 1300

And confirmed by testing: renaming /etc/config/mwan3 and restarting Tailscale makes the exit node work perfectly, the default routes appear in table 52 as expected. Restoring the file breaks it again.

So the sequencing (sleep, rc.local) won't help here — it's not a race condition. Tailscale intentionally skips installing those routes when it detects mwan3, regardless of start order.

The question is: what is Tailscale expecting mwan3 to do with those routes, and why isn't mwan3 doing it? Or alternatively, is there a way to tell Tailscale to install the default routes in table 52 even when mwan3 is present?

You did not even search?

Yes, I already found and read that post too.

Aside from the fact that it's 3 years old and things have certainly changed since then, the user's problem in that thread is completely different from mine. He wants to load balance between WireGuard and Tailscale using mwan3. I'm using mwan3 only to manage failover between my main FTTH connection and a 4G backup.A completely different scenario. On top of that, I don't see any clear solution in that thread either.

Exactly.
You want to re-write Tailscale...

But, it is, practically, abandoned; because: it serves its function.
It did so, as you pointed out, 3 years ago...

Can't answer your questions, but then I would simply try to fix the issue myself, to make it work. Thus

a) patch the tailscale src (you found the code in question already, it seems)

b) or add the missing routing mods in rc.local . Should work with both mwan3 and tailscale running. Simplest solution, for testing, at least. And then to find a suitable hotplug trigger, when to do the patching.

Tailscale and mwan3 iptables are simply incompatible and don't work together and there's no way of resolving this.

As you've discovered for yourself, Tailscale explicitly searches for and bypasses mwan3 and it needs to do this in order to prevent a routing loop, due to Tailscale's architecture.

The mwan3 nftables port which can be found here works perfectly with Tailscale, although has to be configured explicitly to do so, otherwise it will continue to function just like legacy mwan3 iptables and Tailscale will bypass it. This is to maintain backward compatibility.

Instructions on how to configure mwan3 nftables to work with Tailscale are in the documentation.

I assume he is using mwan3 iptables and doesn't know about mwan3 nftables (confirmed by his noting the legacy mwan3 warnings)

If he were using mwan3 nftables and had followed the specific Tailscale configuration instructions in the documentation, then it would work. I added explicit functionality to mwan3 nftables to allow it to be able to co-exist peacefully with and correctly manage Tailscale routes.

@drut is using mwan3 nftables with Tailscale quite happily.

He used to have a (necessarily ugly) workaround in mwan3.user for the legacy mwan3 iptables, although this didn't make Tailscale able to benefit from mwan3 failover, just made it function as if mwan3 were not installed.