Beryl AX OpenWrt Mobile Office Router with Antigravity CLI
TL;DR: I turned a GL.iNet GL-MT3000 into a mobile-office router for garden and travel work. Pixel 8 over USB-C as WAN,
Mobile_Netas my private Wi-Fi, SQM CAKE for calls, encrypted DNS, and ad blocking. The interesting part: I set almost all of it up through Antigravity CLI over SSH, while debugging real router state instead of copy-pasting forum commands.
I wanted a small router I could throw into a bag, bring to the garden, connect to my phone, and use as a real work network.
Not a phone hotspot.
A small private network with my own SSID, DNS filtering, encrypted DNS, and traffic shaping for calls.
The hardware was already sitting on my desk: a GL.iNet GL-MT3000, also known as the Beryl AX. It runs OpenWrt, has Wi-Fi 6, USB 3.0, a 2.5G port, and enough CPU for a proper travel-router setup.
The phone was a Pixel 8.
The workflow was the part that made it fun. I did not sit there with a pile of wiki tabs and a terminal full of half-remembered UCI commands. I drove the setup through Antigravity CLI. It SSH’d into the router, checked packages, read dmesg, installed drivers, wrote UCI config, and verified each change from the actual device.
I knew the architecture I wanted. Antigravity CLI handled the repetitive execution and the boring diagnostics.
The final shape is simple:
Pixel 8 USB tether -> OpenWrt GL-MT3000 -> Mobile_Net -> laptop
Because this is OpenWrt, that simple diagram hides a lot of useful machinery.
The Result, Up Front
The final setup:
| Feature | Status |
|---|---|
| Android USB tethering | Working via usb0 |
| Phone tested | Pixel 8 |
| Router | GL.iNet GL-MT3000 / Beryl AX |
| OpenWrt | 25.12.3 sysupgrade image |
| Local Wi-Fi | Mobile_Net on 2.4 GHz and 5 GHz |
| SQM | CAKE on usb0 |
| Default SQM profile | balanced, 100/25 Mbit/s |
| DNS | https-dns-proxy + OpenWrt adblock |
The router still had plenty of headroom: about 95% CPU idle, 346 MB RAM available, and 198 MB overlay storage free after installing the packages.
The Workflow
The useful part of Antigravity CLI was not that it generated commands. It kept checking the machine in front of it.
It SSH’d into the router, discovered the actual platform, and found:
Model: GL.iNet GL-MT3000 (Beryl AX)
Architecture: MediaTek Filogic / aarch64_cortex-a53
OpenWrt: 25.12.3
That mattered because the old tutorials I had found were not written for this stack. They assumed:
- older OpenWrt
opkgiptables- often rooted Android
- often RNDIS tethering
My router had:
- OpenWrt 25.x
apkfirewall4nftables- a Pixel 8 using CDC-NCM
Antigravity CLI compared the guide against the router, noticed the package manager difference, checked kernel logs, and adjusted.
The loop became:
inspect state
apply one change
reload service
verify output
adjust when reality disagrees
That loop is the difference between generated router commands and a working router.
The First Wall: Android USB Tethering Is Not Just USB Tethering
The old guides I found were mostly written for older OpenWrt releases and rooted Android phones. They used opkg, iptables, and RNDIS assumptions.
That was already outdated for this setup.
OpenWrt 25.x uses apk, and firewall handling is now firewall4 with nftables. The Pixel 8 also did not use the old path I expected. It needed CDC-NCM support.
The package set that mattered was:
apk update
apk add kmod-usb-net-rndis kmod-usb-net-cdc-ether kmod-usb-net-cdc-ncm
The important one for the Pixel 8 was kmod-usb-net-cdc-ncm. Without it, the phone could be physically connected but never appear as a useful network interface.
Once the driver was in place, OpenWrt saw the phone as usb0:
usb0 UP 10.91.215.62/24
That was the first real milestone. The router had a WAN interface coming from the phone.
The annoying part before that: the first cable produced USB enumeration errors:
device descriptor read/64, error -71
unable to enumerate USB device
That was not an OpenWrt problem. It was the cable. Switching to a better USB-C cable made the router see a SuperSpeed USB device, and only then did the driver question matter.
The OpenWrt config after that was straightforward: create a DHCP interface on usb0, add it to the WAN firewall zone, and let the router NAT local Wi-Fi clients behind the phone.
For TTL normalization, the old iptables mangle rule becomes an nftables include under firewall4:
oifname "usb0" ip ttl set 65
oifname "usb0" ip6 hoplimit set 65
I am deliberately calling this TTL normalization here rather than pretending it is just a magic performance tweak. Depending on your mobile plan and carrier terms, this may or may not be allowed. Know what you are doing before copying this part.
Broadcasting the Actual Work Wi-Fi
The router broadcasts one SSID on both bands:
Mobile_Net
Near the router, the laptop got a very good 5 GHz link:
RX rate: 1200.9 Mbit/s
TX rate: 1200.9 Mbit/s
Expected throughput: ~979 Mbit/s
At one point the laptop moved to 2.4 GHz instead:
RX rate: 154.8 Mbit/s
TX rate: 286.7 Mbit/s
Expected throughput: ~245 Mbit/s
That is still usable, but for calls and work near the router I would prefer 5 GHz. Splitting the SSIDs into Mobile_Net_5G and Mobile_Net_2G is probably the next practical tweak.
SQM: The Part That Matters for Calls
Mobile links are strange. A speed test can look good while calls still feel bad.
The problem is not only bandwidth. It is queueing and jitter.
I installed SQM with CAKE:
apk add sqm-scripts luci-app-sqm kmod-sched-cake
Then configured it on usb0. After measuring more, the useful tuning values looked like this:
| Profile | Download | Upload | Use Case |
|---|---|---|---|
stable | 17 Mbit/s | 5 Mbit/s | Calls on weak signal |
balanced | 100 Mbit/s | 25 Mbit/s | Default work mode |
fast | 200 Mbit/s | 40 Mbit/s | Strong 5G |
max | 270 Mbit/s | 50 Mbit/s | Near 300 Mbit/s downlink |
The current default is balanced. The router has no problem handling this. The CAKE queues were clean and CPU stayed mostly idle.
The Latency Reality Check
This is where the setup became honest, but also where I do not want to over-claim. I only tested this indoors so far, not yet in the garden where I actually want to use it.
The local Wi-Fi path was fine:
Laptop -> router:
0% packet loss
avg ~10 ms
max ~34 ms
The cellular path was more variable:
Router usb0 -> 1.1.1.1:
0% loss
avg ~131 ms
max ~534 ms
The lesson is simple: the router can shape queues, filter DNS, and provide a stable Wi-Fi network. It cannot make a bad cellular moment good.
For Zoom, the real test still has to happen outside. I need to compare Vodafone vs o2/Telefonica at the actual garden location, keep the laptop on 5 GHz, and use a more conservative SQM profile during important calls.
If this becomes a serious everyday remote-work setup, a dedicated 5G CPE near the window with Ethernet into the GL-MT3000 is probably better than phone tethering.
No amount of router tuning fixes a bad radio moment.
Encrypted DNS and Ad Blocking
I also added encrypted DNS and ad blocking.
apk add https-dns-proxy luci-app-https-dns-proxy
apk add adblock luci-app-adblock luci-i18n-adblock-de
The router now forwards local DNS through DoH and blocks ad/tracker domains before they leave the network:
Client on Mobile_Net -> dnsmasq + adblock -> https-dns-proxy -> DoH upstream
The first successful adblock run loaded 273,763 blocked domains using the adguard, adguard_tracking, and certpl feeds.
The quick check:
nslookup doubleclick.net 127.0.0.1
nslookup openai.com 127.0.0.1
Ad/tracker domains returned NXDOMAIN, while normal domains still resolved.
Outlook
The setup works, but a few improvements are obvious:
- split the SSIDs into
Mobile_Net_5GandMobile_Net_2G - add
Mobile_Guestfor visitors - add Travelmate for hotel/campsite Wi-Fi and captive portals
- add WireGuard for public-Wi-Fi mode
- test Vodafone vs o2/Telefonica outside in the actual garden
- consider a dedicated 5G CPE if this becomes a daily setup
5G CPE near window -> Ethernet -> GL-MT3000 -> Mobile_Net
That would keep OpenWrt doing what it is good at, while a dedicated modem handles the cellular radio.
The Lesson
This project reminded me why I like OpenWrt.
The GL-MT3000 is a tiny Linux machine, but it is not pretending to be a general-purpose server. It is a network appliance with just enough programmability to become exactly the router I wanted.
The final setup is not just “phone hotspot, but with more steps”.
It is a mobile work network:
- one SSID for my devices
- USB tether as WAN
- SQM for calls
- encrypted DNS
- ad blocking
- a clear path toward travel Wi-Fi and captive portal handling
- SSH-debuggable when something breaks
The remaining bottleneck is not the router. It is the cellular link.
That is a useful boundary to discover. Once the local network is stable, the next improvements are physical: phone placement, carrier choice, and eventually maybe a real 5G modem.
The Antigravity CLI part of this was not “the tool magically knew networking.” It was more mundane and more useful: it kept state, ran the checks, noticed when assumptions failed, and turned a long OpenWrt setup into an interactive debugging session.
I still had to decide what good looked like.
Antigravity CLI made getting there much faster.
The views and opinions expressed here are my own and do not reflect those of my employer.