Initial skills documentation — 25 categories, all SKILL.md + references + scripts
This commit is contained in:
+80
@@ -0,0 +1,80 @@
|
||||
# UniFi Backup Restore Pitfalls (v10.0.162, Jul 2026)
|
||||
|
||||
## The Core Problem
|
||||
|
||||
UniFi `.unf` backup files are **encrypted BSON**. They cannot be read by:
|
||||
- `zipfile` (Python) — throws `BadZipFile`
|
||||
- `bsondump` (MongoDB) — reports "invalid BSONSize"
|
||||
- `mongorestore` — can't parse the encryption
|
||||
|
||||
The ONLY way to restore a `.unf` is through the UniFi `ace.jar restore` command, which decrypts and imports the data into a running MongoDB.
|
||||
|
||||
## Failed Restore Approaches
|
||||
|
||||
### 1. CLI: `java -jar ace.jar restore <file>` (FAILED)
|
||||
|
||||
**Error:** `NoSuchBeanDefinitionException: No qualifying bean of type 'com.ubnt.service.system.status.o0OO'`
|
||||
|
||||
**Root cause:** `ace.jar restore` instantiates the FULL Spring application context, not just a MongoDB connection. It requires all UniFi service beans to be available. Running it in isolation (even with just MongoDB) fails because the Spring context expects the complete application environment.
|
||||
|
||||
**Attempted workarounds that also failed:**
|
||||
- SIGSTOP the running UniFi Java process, then run restore → Spring context collision
|
||||
- SIGKILL the process → entrypoint restarts it
|
||||
- One-off Docker container with just mongod + ace.jar → same Spring bean missing
|
||||
|
||||
### 2. API: `POST /api/s/default/cmd/backup` (FAILED)
|
||||
|
||||
**Error:** `{"meta":{"rc":"error","msg":"api.err.NoSiteContext"}}`
|
||||
|
||||
**Root cause:** In UniFi 10.x, even with valid authentication (`unifises` cookie from `/api/login` → `{"meta":{"rc":"ok"}}`), the backup/restore API endpoints require a site context. `/api/self` returns admin details correctly, but any site-scoped endpoint fails.
|
||||
|
||||
**Prerequisites that were configured correctly and still failed:**
|
||||
- Admin with `super_site_permissions: ["super"]`, `is_super: true`, `super_site_role: "super"`
|
||||
- Privilege records with ObjectId `admin_id` and `site_id` for both "super" and "default" sites
|
||||
- Role: `SUPER_ADMIN`, permissions: `["ALL"]`
|
||||
|
||||
**Attempted endpoints that all return NoSiteContext or Invalid:**
|
||||
- `/api/s/default/cmd/backup` (with `cmd: "list-backups"` or `cmd: "restore"`)
|
||||
- `/api/s/super/cmd/backup`
|
||||
- `/api/s/default/cmd/system`
|
||||
- `/api/system/backup`
|
||||
- `/api/system/backup/list`
|
||||
- `/api/system/backup/restore`
|
||||
|
||||
## What DOES Work
|
||||
|
||||
### Fresh deploy + re-adopt devices
|
||||
|
||||
When the controller is deployed fresh (no backup restore), devices that were previously adopted to another controller will try to inform but fail with "inform decryption failed." To re-adopt:
|
||||
|
||||
1. SSH into each UniFi device
|
||||
2. Run: `set-inform http://<controller-ip>:8080/inform`
|
||||
3. The device appears in the controller UI as "pending adoption"
|
||||
4. Click "Adopt" in the UI
|
||||
|
||||
### Backup restore via the UI Setup Wizard
|
||||
|
||||
On FIRST boot of `jacobalberty/unifi`, the setup wizard at `https://<host>:8443` offers a "Restore from Backup" option. This is the only reliable path to restore a `.unf` file on v10.x.
|
||||
|
||||
### What to check before deploying to avoid this
|
||||
|
||||
1. **Always export a `.unf` before decommissioning** the old controller
|
||||
2. **Store the `.unf` in S3** — don't rely on it surviving on the server
|
||||
3. **Note the old controller version** — major version jumps (9.x → 10.x) add restore risk
|
||||
4. **Document device SSH credentials** — needed for re-adoption if restore fails
|
||||
|
||||
## Dual-Storage Architecture Trap
|
||||
|
||||
The `jacobalberty/unifi` Docker image uses TWO storage locations that can diverge:
|
||||
|
||||
```
|
||||
Host /opt/unifi → Container /config (bind mount: system.properties, certs, old backups)
|
||||
Docker volume → Container /unifi (anonymous: MongoDB data, live backups, sites)
|
||||
```
|
||||
|
||||
The container symlinks `/usr/lib/unifi/data` → `/unifi/data`. When running a one-off container for restore, you MUST use `--volumes-from` to access the anonymous volume. Simply bind-mounting `/opt/unifi:/config` only gives you the stale config files, not the live MongoDB.
|
||||
|
||||
To inspect the anonymous volume path:
|
||||
```bash
|
||||
docker inspect unifi-controller --format '{{json .Mounts}}' | python3 -m json.tool
|
||||
```
|
||||
Reference in New Issue
Block a user