---
type: system
name: uos-server
display_name: UOS Server (UniFi OS Server)
last_compiled: 2026-06-26
compiled_by: GURU-5070/claude-main
sources:
  - session-logs/2026-06/2026-06-21-howard-unifi-pfsense-control-verbs.md
  - 2026-06-26 Rocky 9.1->9.8 host OS patch (mike)
backlinks:
  - systems/jupiter
  - systems/pfsense
  - clients/cascades-tucson
  - clients/internal-infrastructure
---

# 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.8** (kernel `5.14.0-687.17.1.el9_8`; last patched 2026-06-26), 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
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:
```bash
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`:
```bash
# 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):
```bash
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.

## Host OS maintenance (Rocky)

The UniFi app self-updates (the `uosserver-updater.service` rebuilds the rootless podman
container; UOS Server **5.1.19** / Network **10.4.57** as of 2026-06-26). The **host OS is
NOT auto-patched** — it must be updated manually over SSH. The two layers are independent:
patching the host does not touch the container/UniFi data (named podman volumes persist).

**Procedure** (root via the fleet SSH key):
```bash
ssh -i <key> root@172.16.3.29 'dnf -y update'   # ~few min; kernel updates need a reboot
ssh -i <key> root@172.16.3.29 'systemctl reboot' # controller drops briefly; APs keep serving WiFi
# verify after ~3-4 min:
ssh -i <key> root@172.16.3.29 'uosserver status'                  # container Up (healthy)
ssh -i <key> root@172.16.3.29 'curl -sk -o /dev/null -w "%{http_code}\n" https://127.0.0.1:11443/'  # 200
```
- **Safety net:** daily UniFi auto-backups live at
  `~uosserver/.local/share/containers/storage/volumes/uosserver_var_lib_unifi/_data/backup/autobackup/`
  (newest `autobackup_<ver>_<date>.unf`) — survives the OS update. For the OS layer itself,
  a virsh snapshot of the **"Unifi"** VM on [[jupiter]] is the rollback point (optional).
- **Reboot impact:** only central management/stats drop while the VM reboots (~30-60s back to
  SSH, ~3-4 min to container healthy); APs/switches keep forwarding traffic the whole time.
- **History:** 2026-06-26 — Rocky **9.1 -> 9.8** (362 pkgs, kernel `162.6.1.el9_1` ->
  `687.17.1.el9_8`, full security backlog cleared); clean reboot, controller back healthy.

## Related tooling — pfSense gateway layer (works together)

This UOS controller and the **pfSense gateway tooling** are the two halves of the **`unifi-wifi`
skill**, and they're designed to be used together at a single site:

- **This UOS server** = the UniFi side — APs/switches/clients across ~49 sites, queried via the
  Mongo path above (and the `gw-audit`/`gw-control` verbs for UniFi *gateways*).
- **[[pfsense]]** = the gateway side — when a site's gateway is a pfSense (not a UniFi USG/UXG/UCG),
  the same `gw-audit`/`gw-control` verbs auto-dispatch to the pfSense SSH backend
  (`pfsense-ssh.sh` + `pfsense-gwc.php`, cred `clients/<slug>/pfsense-firewall`).

A very common ACG topology is **UniFi APs/switches on this controller behind a pfSense gateway** —
e.g. [[cascades-tucson]] and the ACG office itself. At such a site you drive WiFi/switch work
through this UOS Mongo path and gateway work (WAN/firewall/port-forwards/blocking) through the
pfSense backend; `gw-audit <site>` covers both because it reports `num_gw=0` (no UniFi gateway) and
then runs the pfSense audit. So one skill spans the whole site regardless of gateway vendor.

## Backlinks
- [[jupiter]] — hypervisor (virsh "Unifi" VM) + NPM (`172.16.3.20:7818`, the `:11443` proxy).
- [[internal-infrastructure]] — ACG internal infra index.
- [[pfsense]] — the gateway half of the `unifi-wifi` skill (pfSense SSH backend); pairs with this UOS controller.
- [[cascades-tucson]] — example UniFi-on-UOS-behind-pfSense site (the pfSense backend was validated there).
