How I Built a Tiny WAN Failover Tool for My 8‑MB OpenWrt Router (and Why mwan3 Wasn’t an Option)
1. The Problem: When the Internet Goes Down, So Does My Home Network
Like many of us, I rely on a wired broadband connection for my home internet. But things happen—the provider goes offline for maintenance, a cable gets cut, or (let’s be honest) you forget to pay the bill. When that happens, I wanted my router to automatically switch to a backup connection: a Wi‑Fi hotspot from my phone.
I’m running OpenWrt on a tiny Xiaomi Mi Router C4 . It’s a cheap, reliable device, but it comes with severe storage constraints. Here’s what the filesystem looks like:
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/root 6912 6912 0 100% /rom
tmpfs 28584 336 28248 1% /tmp
/dev/mtdblock9 5760 5628 132 98% /overlay
overlayfs:/overlay 5760 5628 132 98% /
Only ~5.7 MB of writable flash are available, and I’m already using 98% of it. Every kilobyte counts. I needed a solution that would fit into this cramped space and still do the job reliably.
2. Existing Solutions: mwan3 – The Obvious Choice
The most popular tool for multi‑WAN management on OpenWrt is mwan3. It’s mature, well‑documented, and offers:
- Load balancing across multiple connections
- Policy‑based routing (e.g., specific IPs or ports through specific interfaces)
- Advanced failover with custom tracking (ICMP, DNS, ARP)
- A full LuCI web interface
On paper, mwan3 should be able to handle my failover scenario. But when I looked at its requirements, I hit a wall.
Why mwan3 Didn’t Fit
- Storage footprint: mwan3 itself is not huge, but its dependency chain (iptables extensions, tracking modules, and the LuCI UI) quickly grows beyond what I could comfortably afford on an 8‑MB flash device. Installing everything would have consumed the little remaining space I had.
- Memory overhead: mwan3 introduces persistent tracking processes and conntrack load, which can become noticeable on low‑memory devices (64 MB RAM) under heavy NAT usage. It’s not “several MB” per se, but the cumulative effect of conntrack and multiple trackers can strain the system.
- Complexity: Configuring mwan3 involves defining interfaces, members, policies, and tracking rules—powerful, but overkill for my simple “switch to backup when primary is down” use case.
I also considered other lightweight options like ifplugd or custom scripts that watch the default gateway, but they either lacked quality‑based switching or required too much hand‑tuning.
3. Why I Decided to “Reinvent the Wheel”
I realised that my requirements were actually quite simple:
- Periodically check if the primary interface is still usable.
- Measure not just “up/down”, but also latency, packet loss, and jitter—so I can switch before the link becomes unusable.
- Automatically change the default route to the best available interface.
- Be extremely lightweight—preferable under 100 KB of flash, with no kernel modules or extra daemons.
- Provide a basic web interface to see status and manually override.
Nothing on the market met all these criteria at once. So I decided to write my own tool. I called it wanmon (WAN Monitor).
4. The Birth of Wanmon: A Minimalist Approach
Wanmon is a collection of shell scripts that work together in three independent stages:
-
Measurement (
wm-state.sh) – sends pings to a configurable host and records latency, loss, and jitter for each interface. -
Decision (
wm-select.sh) – computes a quality score for each interface, applies smoothing and hysteresis, and picks the best candidate. -
Application (
wm-apply.sh) – updates the kernel routing table accordingly.
This separation of concerns makes wanmon a mini‑SD‑WAN controller in its own right. The key idea is that connectivity is not binary. A WAN link can be “up” but still unusable due to high latency or packet loss. Wanmon treats network quality as a continuous cost function rather than a reachability flag.
The score for each interface is defined as:
score = (latency + jitter) + (loss² / loss_divisor) + bias
The lowest score wins. Smoothing and hysteresis prevent flapping. The entire system uses no iptables, no conntrack, and no heavy dependencies—just jq for JSON parsing (which I already had installed). The total size of all scripts and the web interface is ~80 KB.
How Wanmon Compares to mwan3
| Aspect | mwan3 | wanmon |
|---|---|---|
| Storage | ≥1–2 MB (with dependencies) | <100 KB |
| RAM usage | Moderate (daemon + conntrack + trackers) | Minimal (fork‑exec loop) |
| Configuration | Complex (policies, members, trackers) | Single JSON file |
| Primary use | Load balancing + failover | Failover only |
| Decision logic | Reachability (up/down) | Latency + loss + jitter (cost‑based) |
| Web interface | Heavy LuCI integration | Lightweight standalone HTML or single LuCI page |
| Modifiability | Hard (C/shell, complex architecture) | Easy (simple shell, tweakable in minutes) |
| Policy‑based routing | Yes | No |
| Per‑connection tracking | Yes | No |
| QoS integration | Possible via scripts | Not included |
This table shows that wanmon is not a replacement for mwan3 in all scenarios—it deliberately trades flexibility for minimalism.
5. Wanmon in Action – A Real‑World Setup
On my Xiaomi C4, I connected my phone’s Wi‑Fi hotspot as a second WAN interface (via a USB‑to‑Wi‑Fi dongle or a travel router). Wanmon automatically detects both the wired PPPoE interface (wan) and the hotspot interface (wwan). I configured a bias (metric) to prefer the wired link as long as its quality is acceptable.
When the wired connection degrades (e.g., ISP outage), wanmon notices the increased latency or packet loss. The score rises, and after the hysteresis threshold is crossed, it switches the default route to the hotspot. Once the wired link recovers, it switches back—smoothly and without user intervention.
The web interface at http://router-ip/wanmon.html gives me a clear dashboard showing:
- Daemon status
- Current default route
- Live scores and telemetry (latency, loss, jitter) per interface
- A dropdown to manually force any interface
All of this fits within the 5.7 MB overlay—leaving room for other essential tools.
6. Conclusion: Sometimes, Less Is More
mwan3 is a fantastic tool for routers with ample resources and complex routing needs. But for devices like the Xiaomi C4—with just 8 MB flash and 64 MB RAM—it’s often overkill. Wanmon proves that you don’t need a heavyweight solution to get reliable, intelligent WAN failover.
If you’re in a similar situation—struggling to squeeze more functionality into a small OpenWrt device—I encourage you to try wanmon. It’s open source, easy to customise, and it just works.
Check it out on GitHub: https://github.com/ng256/WanMonitor
Have questions or ideas? Feel free to open an issue or submit a pull request. Let’s keep our routers smart, even when they’re small.
Top comments (0)