Files
claudetools/wiki/systems/uos-server.md
Mike Swanson 4ef6a9a3b0 sync: auto-sync from GURU-5070 at 2026-06-15 17:49:06
Author: Mike Swanson
Machine: GURU-5070
Timestamp: 2026-06-15 17:49:06
2026-06-15 17:49:23 -07:00

5.6 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 domain Unifi (id 1). virsh list to confirm running.
  • App stack (inside guest): UniFi Network = ace.jar (Java) + classic MongoDB ace on 127.0.0.1:27117, plus unifi-core (Postgres) for UniFi-OS identity/integration. All of it runs inside a rootless podman container uosserver (host user uosserver, uid 1000) — so the app files and mongo are NOT on the guest rootfs.
  • ui.com cloud: host id 2d6b654d-9b79-4eaa-b2e1-52062a5690ef in 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: a dedicated fleet key is authorized as root on the guest — vault infrastructure/uos-server-ssh-key (the private key is base64 in field ssh-private-key-b64; vault-helper can't store multiline). Any fleet machine can use it:

bash .claude/scripts/vault.sh get-field infrastructure/uos-server-ssh-key credentials.ssh-private-key-b64 \
  | base64 -d > /tmp/uos && chmod 600 /tmp/uos && ssh -i /tmp/uos root@172.16.3.29 'id'

.claude/scripts/uos-mongo.sh resolves this key automatically (no setup). GURU-5070's personal key is also authorized (legacy). 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-Key vs https://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) for https://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 by site_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 device with adopted:false. If db.device.count({adopted:false}) is 0, 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.