Custom OpenWrt firmware for self-organizing mesh networks using batman-adv (L2) and Yggdrasil (overlay). Nodes auto-configure on first boot with zero manual setup.
Firmware & downloads · Live coverage map · Documentation · Getting started (A4) · Peering agreement
Internet
|
[Bumblebee nodes] ← L3 gateways (WireGuard VPN, guest isolation, DoH)
/ | \
batman-adv mesh (802.11s) ← L2 transport
/ | \
[Bee nodes] ← L2 relays (minimal, low-power)
Two node roles:
| Role | Function | Packages | Devices |
|---|---|---|---|
| Bumblebee | L3 Gateway — full stack | batman-adv, Yggdrasil, WireGuard, tc, DoH | AXT1800, MT3000, MT6000, AX53U, AP3000 Outdoor |
| Bee | L2 Transport — mesh relay | batman-adv, Yggdrasil | AR300M16, CPE710 |
- Private WiFi (
Parahub, 5GHz) — WPA3/SAE, 802.11r/k/v seamless roaming across all nodes - Public WiFi (
parahub.io/free, 2.4GHz) — open network, client-isolated (guest-isolated on Bumblebees) - Mesh backhaul (802.11s on both bands) — SAE-encrypted, batman-adv BATMAN_V routing
- Yggdrasil overlay — IPv6 management plane, OTA updates, Parahub services at full speed
- Status page (
http://node.parahub.net) — read-only live node status for guests and LAN clients (see below)
Guest device → parahub.io/free → guest zone → policy routing (table 100) → WireGuard VPN → exit
VPN tunnel is auto-configured via heartbeat API. DNS is forwarded through VPN (no leak).
| Device | Target | Role | Notes |
|---|---|---|---|
| GL.iNet GL-AXT1800 (Slate AX) | qualcommax/ipq60xx | Bumblebee | WiFi 6, 512MB RAM |
| GL.iNet GL-MT3000 (Beryl AX) | mediatek/filogic | Bumblebee | WiFi 6, compact |
| GL.iNet GL-MT6000 (Flint 2) | mediatek/filogic | Bumblebee | WiFi 6, 1GB RAM |
| Asus RT-AX53U | ramips/mt7621 | Bumblebee | WiFi 6, DSA switch |
| Cudy AP3000 Outdoor V1 | mediatek/filogic | Bumblebee | WiFi 6 dual-band, outdoor IP65, single PoE |
| GL.iNet GL-AR300M16 (16MB) | ath79/generic | Bee | Tiny, 2.4GHz only |
| TP-Link CPE710 v1 | ath79/generic | Bee | 5GHz outdoor, 23dBi directional |
- Linux x86_64
wget,zstd,make,python3MESH_HEARTBEAT_KEYin environment or in/opt/parahub/.env
./scripts/build.sh <device>The script automatically downloads the OpenWrt Image Builder on first run (~1.5GB per target).
Examples:
./scripts/build.sh axt1800 # GL-AXT1800 Bumblebee
./scripts/build.sh cpe710 # CPE710 Bee
./scripts/build.sh mt6000 # GL-MT6000 Bumblebee
# Custom OpenWrt version
OPENWRT_VERSION=25.12.0 ./scripts/build.sh mt3000
# Extra packages
PACKAGES_EXTRA="nano htop" ./scripts/build.sh axt1800Output firmware lands in output/. A manifest.json is maintained for OTA updates.
Standard OpenWrt sysupgrade:
sysupgrade -v /tmp/openwrt-*-sysupgrade.binOr via LuCI web UI: System > Backup/Flash Firmware.
First boot is zero-touch: the node configures itself, meshes with any Parahub node in radio range and appears in parahub.io/iot within ~5 minutes.
For the host/installer side — node roles, which port takes the internet on each device, cabling do & don't, WiFi networks, address recognition, speed tiers and human-level troubleshooting — see the one-page getting-started sheet:
- Live version (always current): https://parahub.io/print/mesh.html
- Offline copy (synced on every release):
docs/getting-started.html— open in a browser; Ctrl+P prints it as a single A4.
The sheet describes a node operating inside the Parahub fleet (managed from parahub.io/iot). If you run your own backend, read it as the reference deployment.
The 99-parahub-mesh uci-defaults script runs once on first boot and configures everything:
- Identity — derives hostname and unique subnets from hardware MAC (
Parahub-XXXX) - Network — batman-adv mesh, private bridge, guest isolation (Bumblebee), WireGuard stub
- WiFi — dual-band mesh backhaul, private AP (802.11r roaming), public AP
- Firewall — zone-based (lan/guest/wan/vps_gateway/yggdrasil), guest kill-switch
- Services — heartbeat (5min), gateway health check (2min), OTA updates (nightly), status page (second uhttpd on
:8080) - Yggdrasil — generates node keys, connects to VPS peers (Bumblebee) or multicast (Bee)
Nodes check manifest.json nightly, compare SHA256, and auto-sysupgrade. Node identity (MAC, subnets, keys) is preserved across updates via sysupgrade.conf.
Every 5 minutes, nodes phone home to the Parahub API with status: uptime, clients, batman neighbors and per-link throughput (topology reporting), Yggdrasil address, burned-in hardware MACs (label-based claiming), and — on the elected guest terminator — current guest DHCP leases. The API responds with VPN configuration, sharing budgets, the guest-gateway election result, paid client lists, the node's map coordinates, and firmware update info.
Beats are also triggered out of band — by a guest DHCP lease and by guest-interface bringup — so a device with a full-speed pass is unshaped within seconds of joining instead of at the next scheduled beat.
Two mechanisms, one per concern:
- Internet gateway (local) —
parahub-gw-checkmonitors WireGuard tunnel health. When the tunnel is active and healthy, it promotes the node togw_mode=serverin batman-adv, advertising itself as an internet gateway to Bee nodes. - Guest terminator (server-side) — the heartbeat API elects exactly one Bumblebee per mesh island to serve guest-VLAN DHCP and terminate guest traffic into its VPN;
parahub-guest-gatewayapplies the result. A single DHCP server per shared guest VLAN — no lease racing between Bumblebees.
Every node serves a read-only status page at http://node.parahub.net — exit state, neighbor radio links, the visitor's own speed tier, and a link to the node's spot on the coverage map. It keeps working with the internet down. The page runs as a second uhttpd instance (:8080, docroot /www-status), so LuCI stays unreachable from the guest zone as before. Resolution is split-horizon: the node's own dnsmasq plus a 10.255.255.1/32 loopback anycast on every node — plain routing delivers guests to the elected terminator's page and LAN clients to their own node's. The name is deliberately plain HTTP outside parahub.io: the platform serves HSTS covering its subdomains, which would force-upgrade the page to https that the guest zone rejects.
| Script | Description |
|---|---|
parahub-heartbeat |
Status reporting + VPN auto-config |
parahub-autoupdate |
OTA firmware updates with SHA256 verification |
parahub-gw-check |
Gateway health monitoring + batman-adv mode promotion |
parahub-guest-gateway |
Applies the per-island guest-gateway election result — toggles guest-VLAN DHCP (called by heartbeat) |
parahub-speed-control |
Per-client bandwidth shaping on guest network |
parahub-vps-setup |
WireGuard tunnel configuration (called by heartbeat) |
parahub-mullvad |
Optional Mullvad VPN for lower-latency guest exit |
parahub-ygg-acl |
Yggdrasil inbound access control (nftables whitelist) |
The firmware source is MIT licensed. The network — the free transit that nodes donate to each other and to guests — follows the Parahub Mesh Peering Agreement, adopted from the Pico Peering Agreement v1.0 (CC0).
That agreement is a draft pending legal review and is not yet in force: it states how the mesh is meant to work and how guest data is handled, and it binds no node owner until a final version is adopted. What a node reports about itself and about connected guests is described in section 5.7 and in the Privacy Policy.
MIT — firmware source code. See PEERING.md for the network peering terms.