Lock your UniFi 5G modem to specific LTE/5G bands — and make it stick.
For Ubiquiti U5G, U5G-Max and U5G-Max-Outdoor modems. Runs from any Linux box on your LAN (or a Docker container). Nothing is installed on your gateway, and no firmware is modified.
You probably do if your 5G WAN drops for 1–3 minutes at a time, several times a week, even though the UniFi console shows a strong signal.
Check the UniFi console under Internet → your 5G WAN. The tell-tale pattern:
| What you see | What it means |
|---|---|
Primary Tech: 5G NSA |
Your 5G rides on an LTE "anchor" band. If the anchor stumbles, the whole connection drops. |
| Signal strength (RSRP) is good (better than −90 dBm) | The tower is close enough — distance is not your problem. |
| LTE Radio Health (SINR) is poor (below ~10 dB) | The anchor band is noisy. This is what tears down your connection. |
| A new IP address after every drop | The modem isn't just losing packets — it's re-registering from scratch. |
In the UniFi system log (Settings → System Log, filter Internet & WAN)
the same problem looks like repeated NETWORK_WAN_FAILED / RESTORED pairs,
often with ISP_PACKET_LOSS just before, and sometimes MBB_SIM_INSERTED
(the modem resetting itself) even though nobody touched the SIM.
Real example this tool was built for: anchor stuck on B3 with SINR 7 dB and RSRP −70 dBm. Excluding B3 moved the anchor to B7 → SINR 11.2 dB and a stable session. Same hardware, same location, same tower — just a quieter band.
Two obstacles, both outside your control:
- UniFi has no band selection in the UI. Ubiquiti considers band choice a
carrier matter; the feature request has been open since 2022.
The setting does exist on the modem, via an undocumented CLI
(
uiwwand-ctl) reachable over SSH. - The modem forgets. Its config lives in tmpfs, so any band preference is wiped on every reboot — including reboots the modem does on its own.
So the fix is: set the preference over SSH, then keep re-applying it. That's all this tool does — one ~50-line bash script on a timer.
- A UniFi U5G modem (
UMBBE*model) adopted in UniFi Network. - Device SSH enabled: console → Settings → System → Device SSH Authentication. Note the username; the password is fetched automatically if you use an API key (below).
- A UniFi API key (recommended, so a rotated SSH password doesn't break things): console → Settings → Control Plane → Integrations → Create API Key. Alternatively skip it and hardcode the SSH username/password.
- Your SIM's ICCID — visible in the UniFi console on the 5G WAN page, or by
running
cat /etc/uiwwand.jsonon the modem over SSH. - A Linux host on the same LAN that can reach the modem's IP, with either
Docker, or
bash curl jq sshpass openssh-clientinstalled.
List the bands your carrier actually deploys in your area (a cell-mapping app or your carrier's coverage page will tell you), then remove the noisy one you identified above. Two rules:
- Always leave several bands in the list. If you allow only one and it's unavailable where you are, the modem has nowhere to go and you lose the WAN entirely.
- Don't touch the 5G bands unless the 5G leg itself is the problem — in NSA mode it's usually the LTE anchor that misbehaves.
LTE_BAND=1,7,20,28 in the examples means "any of B1/B7/B20/B28, but never
B3". Numbers are plain LTE band numbers.
git clone https://git.protonord.no/Protonord_public/u5g-bandlock && cd u5g-bandlockThen edit docker-compose.yml:
# docker-compose.yml
services:
u5g-bandlock:
build: .
container_name: u5g-bandlock
restart: unless-stopped
environment:
MODEM_IP: 192.168.1.53
ICCID: "8947000000000000000"
LTE_BAND: "1,7,20,28"
NR5G_SA_BAND: "1,3,28,78"
INTERVAL: 900 # check every 15 min
UNIFI_HOST: 192.168.1.1
UNIFI_API_KEY: your-api-keydocker compose up -d --build
docker compose logs -f # expect: "ok: lte_band=1,7,20,28"The container needs normal LAN access to the modem and the console — no host networking, no privileges.
git clone https://github.com/IBICO74/u5g-bandlock /opt/u5g-bandlock
mkdir -p /root/.config/u5g-bandlock
cp /opt/u5g-bandlock/env.example /root/.config/u5g-bandlock/env
chmod 600 /root/.config/u5g-bandlock/env # then edit it
ln -s /opt/u5g-bandlock/u5g-bandlock.service /etc/systemd/system/
ln -s /opt/u5g-bandlock/u5g-bandlock.timer /etc/systemd/system/
systemctl daemon-reload && systemctl enable --now u5g-bandlock.timer
systemctl start u5g-bandlock.service && journalctl -u u5g-bandlock -n 5Setting the preference does not disturb the connection that's already up — the modem only picks new bands when it next registers. Reboot the modem once (UniFi console → the modem → Restart) to force a re-attach.
Afterwards, verify in the console that LTE Radio Health (SINR) improved and
that the band changed. From then on the tool keeps the preference alive on its
own; you'll see drift: lte_band was «…» — re-applying … in the logs after
each modem reboot.
docker compose down # or: systemctl disable --now u5g-bandlock.timerThen reboot the modem from the console. Because of the tmpfs behaviour it comes
straight back to factory defaults (automatic, all bands) — there is nothing
left behind to clean up.
| Variable | Required | Meaning |
|---|---|---|
MODEM_IP |
yes | The modem's LAN IP |
ICCID |
yes | SIM ICCID |
LTE_BAND |
yes | Allowed LTE bands, comma-separated |
NR5G_SA_BAND |
no | Allowed 5G SA bands |
MODE |
no | Radio access modes, default 5gnr,lte |
UNIFI_HOST + UNIFI_API_KEY |
either this… | Fetch device SSH password live from the Network API |
MODEM_USER + MODEM_SSH_PASSWORD |
…or this | Static SSH credentials |
INTERVAL |
Docker only | Seconds between checks (default 900) |
| Symptom | Likely cause |
|---|---|
Permission denied (publickey,password) |
Device SSH is off, or the username differs — check Settings → System → Device SSH Authentication |
{"error":-1} from the modem |
Wrong ICCID, or a method your firmware doesn't expose |
curl: (22) The requested URL returned error: 401 |
Wrong or revoked UniFi API key |
curl: (22) … error: 502/503 |
The UniFi console is restarting or unreachable (e.g. nightly maintenance) — transient, the next run recovers |
| Band never changes | You haven't rebooted the modem since the first apply |
| WAN goes down after locking | Your allowed list has no band available here — widen it and reboot the modem |
| What | Details |
|---|---|
| UniFi Network API | GET https://<console>/proxy/network/api/s/default/get/setting with an X-API-KEY header; the mgmt object carries x_ssh_username/x_ssh_password (device SSH credentials). Read-only — nothing is written to the console. Answers HTML/5xx while the console restarts, which shows up as one failed run. |
Modem uiwwand-ctl (undocumented) |
JSON-RPC on stdin over SSH (Dropbear, password auth via sshpass): get-radio-pref and set-radio-pref with iccid, mode, lte_band, nr5g_sa_band. The preference lives in tmpfs on the modem. |
| Runtime | bash curl jq sshpass openssh-client; the Docker image is alpine:3.20 with the same packages. No image is published — docker compose builds it locally. |
| Protonord's own instance | The systemd install, where /opt/u5g-bandlock is a symlink to the git checkout: whatever is checked out runs on the next timer tick (every 15 min). Work on a branch in a separate worktree and merge to main to deploy. Config in /root/.config/u5g-bandlock/env (mode 600, never in git). |
| Forgejo → GitHub | Push-mirror from Protonord_public/u5g-bandlock to github.com/IBICO74/u5g-bandlock every 8 h. Changes go issue → branch → PR → merge on Forgejo (pn-forgejo from the workspace VM); main is not branch-protected. |
Developed at Protonord — the Forgejo repo is the source of truth; this GitHub repo is an automatic mirror.
- Tested on U5G-Max-Outdoor (UMBBE631, fw 7.5.3) with UniFi Network 10.5 on a UDM-SE.
- If your modem reports
5gnr-sasupport (get-radio-cap), full 5G Standalone is another route — it drops the LTE anchor entirely. SetMODE=5gnrto try, if your carrier deploys SA on your cell. - Inspired by FRooter/u5g-bandfix, which runs on the Cloud Gateway itself using MongoDB lookups and SSH key installs. This tool deliberately leaves the gateway untouched.
- Use at your own risk: it drives an undocumented CLI on the modem. Nothing is written to persistent storage, so a reboot always restores factory behaviour.