5.1 KiB
type, name, display_name, last_compiled, compiled_by
| type | name | display_name | last_compiled | compiled_by |
|---|---|---|---|---|
| system | uos-server | UOS Server (UniFi OS Server) | 2026-06-15 | GURU-5070/claude-main |
UOS Server (UniFi OS Server)
ACG's self-hosted UniFi OS Server — one controller managing ~49 UniFi sites (Cascades, Khalsa, Quantum, Reliant, VWP, IMC, Cutting Edge, and many remote UDM/UCG consoles adopted into it). Runs as the virsh VM "Unifi" on Jupiter. This article is the single-shot access reference: how to reach it, and how to query its device/client DB directly (the cloud API and the local web UI both hide data this method exposes).
What / where it is
- Guest: Rocky Linux 9.1, hostname-internal "UOS Server". Guest IP
172.16.3.29(ACG internal LAN). - Hypervisor: Jupiter (
172.16.3.20, Unraid) — virsh domainUnifi(id 1).virsh listto confirm running. - App stack (inside guest): UniFi Network =
ace.jar(Java) + classic MongoDBaceon127.0.0.1:27117, plusunifi-core(Postgres) for UniFi-OS identity/integration. All of it runs inside a rootless podman containeruosserver(host useruosserver, uid 1000) — so the app files and mongo are NOT on the guest rootfs. - ui.com cloud: host id
2d6b654d-9b79-4eaa-b2e1-52062a5690efin the Site Manager account.
Reachability — the port gotcha
It sits behind NPM (Nginx Proxy Manager on Jupiter, admin http://172.16.3.20:7818):
| Public hostname | NPM target |
|---|---|
unifi.azcomputerguru.com (443) |
https://172.16.3.29:11443 |
So the UniFi-OS web/API HTTPS port is 11443, not the classic 8443. On 172.16.3.29 directly: open = 11443 (UniFi OS HTTPS), 8080 (inform//status), 8880, 6789, 22 (SSH). Closed = 443, 8443, 8843. Probing :8443/:443 and concluding "unreachable" is the trap — use :11443 (or the unifi.azcomputerguru.com hostname).
Access (the single-shot path)
SSH: our standard key is already authorized as root on the guest. Direct, or jump via Jupiter:
ssh root@172.16.3.29 'id' # direct (office LAN or Tailscale subnet route)
ssh -J root@172.16.3.20 root@172.16.3.29 # via Jupiter
Query the UniFi Network DB (ace) in one shot — use the helper, which pipes Mongo JS
through ssh -> su - uosserver -> podman exec -i uosserver mongo:
# find any device/client by MAC suffix across ALL sites (infra + clients):
bash .claude/scripts/uos-mongo.sh --find-mac 36:c4
bash .claude/scripts/uos-mongo.sh --sites # list site_id -> name
echo 'db.device.count()' | bash .claude/scripts/uos-mongo.sh
bash .claude/scripts/uos-mongo.sh < some-query.js
Raw equivalent (no helper):
echo 'db.device.find({mac:/36:c4$/i}).count()' \
| ssh root@172.16.3.29 'su - uosserver -c "XDG_RUNTIME_DIR=/run/user/1000 podman exec -i uosserver mongo --quiet --port 27117 ace"'
There is no mongo client on the guest host; the shell is /usr/bin/mongo inside the
uosserver container. guest-exec via the QEMU agent is disabled, so drive it over SSH (above).
Keys / auth — what works and what doesn't
- SSH root key on
.29— the reliable way in (this is "the key" for UOS work). Gives root + Mongo + everything. - Cloud Site Manager API key — vault
infrastructure/unifi-site-manager-api(X-API-Keyvshttps://api.ui.com). Lists adopted devices/sites only (/v1/devices,/ea/sites,/v1/hosts). Does NOT authenticate the local integration API (401), even on localhost — it is a cloud key, not the local key. - Local Network integration key "Claude" — exists in
ace.api_key(count 1) forhttps://172.16.3.29:11443/proxy/network/integration/v1/..., but its value is hashed/unrecoverable. If the integration REST API is ever needed, generate a fresh key in the UniFi Network UI (Control Plane -> Integrations), use it once, and vault it. For reads, the Mongo path above is simpler and complete.
Querying notes (ace collections)
device— adopted infrastructure (APs/switches/gateways), all sites, keyed bysite_id. MAC is lowercase colon form (74:83:c2:75:e9:9f).user— clients/stations (wired + wireless endpoints).site—_id(ObjectId; use_id.str) ->desc/name. Build a map to label results by site.rogue— neighbor/over-the-air BSSIDs seen by APs. Not ACG gear — a MAC hit here is someone else's WiFi, ignore it for device hunts.- Pending/unadopted devices: the controller only persists a discovered device into
devicewithadopted:false. Ifdb.device.count({adopted:false})is0, there are no pending devices controller-wide — an "unadopted" device that returns nothing here simply has not reached this controller (not on a network it can discover, or managed by a different console). The cloud API and integration API show adopted gear only, so they cannot find it either; locating it then needs L2/DHCP/ARP on the gateway of the site it is physically cabled to.
Backlinks
- jupiter — hypervisor (virsh "Unifi" VM) + NPM (
172.16.3.20:7818, the:11443proxy). - internal-infrastructure — ACG internal infra index.