Files
family_home_lab/plan.md

10 KiB

Family Home Lab Console — Plan

Adapted from Obsidian notes: FAMILY Enterprise Homelab AI Multimedia Suite, FAMILY S3 Storage Integration & Blueprint, FAMILY DeepSeek Harness (dsh) Home Lab Setup, Home Network Map Overview, Backup System — Borg, Kopia & Restic.

Status: FINAL v3 — approved. Build phase: repo-local code complete (2026-08-24), deployment pending.


1. Goal

A single family console ("landing page") at a local URL where each of the four users (Sam, Jo, Harry, Finn) logs in and gets:

  • A personalised dashboard of available AI + media tools
  • One-click launch of each tool (inline iframe where possible, else window/new tab)
  • Per-user session handling and tool permissions

The console is also the parent interface that the DeepSeek Harness instances hang off (dsh itself is built by another agent — we only define the integration contract here).

2. Where it runs (adapted to my network)

Concern Generic blueprint said Adapted decision
Host machine unspecified .13 nixos-desktop — always-on server, existing Docker host (15.5 GB RAM), already runs Open WebUI/OmniRoute/Langfuse
Reverse proxy dedicated Caddy container in compose stack Reuse existing Caddy on .35 — it already proxies *.home.lab; no duplicate proxy/ports 80/443 conflict
Local DNS Pi-hole records Not needed — using public domain *.lab.audasmedia.com.au (real TLD, always resolves; *.home.lab failed as it's not a registered TLD)
LLM routing deploy omniroute container in stack Reuse existing OmniRoute .13:20128/20129
Object storage deploy Garage in stack Fresh Garage deployment in our own stack, data on /mnt/data/family-home-lab/garage/ (new subdir; Takeout landing zone untouched). Old garage-garage-1 test instance retired after data check

Directory layout (on .13)

/home/sam/Docker/Containers/family-home-lab/   # compose project (matches existing convention)
├── docker-compose.yml
├── .env                      # secrets (git-ignored)
├── garage/garage.toml
├── portal/                   # custom FastAPI app
│   ├── main.py               # async web controller
│   ├── auth.py               # user login/session handling
│   ├── database.py           # PostgreSQL + pgvector
│   ├── tasks.py              # background workers (Celery)
│   ├── templates/            # HTMX/Jinja2 frontend
│   └── static/
/mnt/data/family-home-lab/    # heavy data (NOT backed by root drive)
├── garage/garage-data        # S3 object data
├── garage-meta/
└── shared-media/

Repo lives here (family_home_lab working dir) with subfolders per tool category: video/ image/ audio/ docs/ ai/ chat/ — no dsh folder (owned by other agent).

Queue: RabbitMQ container deployed fresh inside this stack (verified none exists on network).

3. Core stack

Component Technology Rationale
Console portal FastAPI + Jinja2 + HTMX lightweight, employable skillset, no SPA build chain needed
Auth per-user accounts (bcrypt password hash), signed HTTP-only session cookies; admin panel for Sam to manage users simple, self-contained; no external IdP overhead for 4 users
Database pgvector/pgvector:pg16 user profiles + preferences now; semantic memory vectors later
Task queue Celery + Redis (downgrade from blueprint's RabbitMQ unless queue UI is wanted) lighter on 15.5 GB RAM shared with existing services; swap-in RabbitMQ is trivial if wanted for resume value
Object storage Garage v1.x S3-compatible pure OSS Rust S3; buckets per user + shared-media; boto3 from portal
Proxy/DNS existing Caddy (.35) + Pi-hole records consistent with rest of network

URLs (final — public domain, no local DNS needed)

All domains resolve via public DNS lab.audasmedia.com.au → 144.6.86.11 → router → .35 Caddy → internal hosts.

Domain Target Tool
console.lab.audasmedia.com.au .35 → .13:8500 The family console (this project)
photo.lab.audasmedia.com.au .13 photopea container Image editing
video.lab.audasmedia.com.au .13 video editor container Video editing
audio.lab.audasmedia.com.au .13 audio container Audio editing
s3.lab.audasmedia.com.au .13 Garage API S3 endpoint (internal/API use)
dsh instances dsh-<user>.lab.audasmedia.com.au Built by other agent — see §6

4. Tool catalogue (phase 1)

Each tool = its own subfolder here, own URL, dockerised with WebUI, mounted against Garage buckets or bind-mounted media dirs.

  • Image: Photopea (self-hosted)
  • Video: KdenLive via LinuxServer webtop/KasmVNC image ⚠️ verify current image name — LSIO deprecated some standalone rdesktop apps
  • Audio: Audacity via LinuxServer webtop image (Zrythm optional phase 2)
  • AI chat: OmniRoute dashboard (.13:20128, omniroute.home.lab) linked/inlined. Open WebUI — dropped; dsh instances will replace it.
  • Docs / Chat: future phases (dsh per-user instances are the chat layer)

5. S3 storage integration (final)

  • Fresh Garage v1.x container in our stack. data_dir = /mnt/data/family-home-lab/garage-data, metadata_dir = /mnt/data/family-home-lab/garage-meta. Ports 3900 (S3 API) / 3902 (web) — old test instance stopped first to free them.
  • Buckets: sam, jo, harry, finn, shared-media.
  • Portal uploads/downloads via boto3 (S3v4 signatures); tools either bind-mount or use rclone/s3fs mounts where they can't talk S3 natively.
  • Backups: add /mnt/data/family-home-lab/ to .13's existing Borg job source list → covered by rsync→.35→.23 chain.
  • /mnt/data's existing Takeout dirs (01_keep/02_review/03_delete/takeout/.thumbs) are never touched.

6. DeepSeek Harness integration contract (NOT building dsh)

Update the dsh Obsidian note to require:

  • Each dsh instance reachable at dsh-<user>.home.lab via .35 Caddy (subdomains, not subpaths — avoids WebSocket/path issues).
  • Console links to the correct instance after login; optionally auto-auth via one-time token passed in query param (to be designed with the dsh agent).
  • dsh containers must be iframe-friendly (correct CSP/X-Frame-Options headers set by Caddy) if embedded inline in the console.
  • Session handling stays inside dsh; the console only handles entry-point routing.

7. Deployment

  1. Stop/retire old garage-garage-1 test instance (after du sanity check of its volume) ✅ done
  2. Apply Caddyfile entries on .35 from deploy/caddy/Caddyfile.snippet (tracked via filechanges extension)
  3. docker compose up -d from /home/sam/Docker/Containers/family-home-lab/ on .13
  4. Create Garage buckets + access keys; first-run admin setup creates Sam's admin account, then Jo/Harry/Finn
  5. Add /mnt/data/family-home-lab/ to Borg backup source list on .13

DNS note: public domain *.lab.audasmedia.com.au is used — no Pi-hole local records required. *.home.lab domains are deprecated (not a registered TLD; resolution unreliable).

8. Resolved decisions

  1. Queue: RabbitMQ (own container in our stack; verified no conflict — Mosquitto :1883 was the false memory)
  2. Video/audio editors: browser-streamed desktop containers ✓
  3. Portal port: 8500 on .13 ✓
  4. Auth: username + password (bcrypt), signed session cookies, all four users ✓
  5. Phase-1 tools: Photopea, video editor, audio editor, OmniRoute link ✓ (Open WebUI dropped — dsh replaces)
  6. Storage: fresh Garage on /mnt/data/family-home-lab/; old test instance retired after du check ✓
  7. Compose location: /home/sam/Docker/Containers/family-home-lab/ ✓
  8. Frontend: FastAPI + Jinja2 + HTMX, server-rendered, no SPA build chain ✓

9. Verified facts (live checks)

  • .13 containers include: omniroute (:20128/29), garage (:3900/3902), n8n, airflow, langfuse, litellm (:4000), mosquitto (:1883), pihole (:53/:8080), pocketbase (:8090), prefect (:4200), minio (:9010/:9090), postgres (:5432/:5433/:5434). No RabbitMQ. Port 8500 free ✓.

10. Build status (repo-local, 2026-08-24)

Item State
portal/ FastAPI app (main/auth/db/tasks/tools/config) ✅ written & compiles
Templates + tokens.css/app.css (9 pages, HTMX polling) ✅ written, all render
docker-compose.yml (portal/db/redis/rabbitmq/garage/worker) ✅ written, config -q valid
Tool containers (photo/video/audio) ✅ media tools LIVE: photo/video/audio.lab.audasmedia.com.au (Photopea/KdenLive/Audacity)
garage/garage.toml + .env.example ✅ written + applied live
First-run admin bootstrap (env) ✅ implemented + verified
Local smoke test (login→dashboard→admin→add-user) ✅ passed — caught+fixed 2 bugs (session_scope, non-fatal broker call)
Deploy to .13 + Garage buckets/keys ✅ core stack live on console.lab.audasmedia.com.au
Caddy rules on .35 ✅ console + photo/video/audio + dsh-sam/jo/harry/finn applied & reloaded
DeepSeek Harness ✅ built here (dsh/) + 4 instances live: dsh-{user}.lab.audasmedia.com.au → .13:3081-3084 (auto/best-chat via OmniRoute)
Tool page workspace files ✅ /tool/{id} lists user's S3 bucket + shared-media
Borg backup path on .13 ⏳ needs sudo edit to backup.nix (snippet provided)

Deployed 2026-08-24: console live + media tools live. Buckets sam, jo-media, harry, finn, shared-media (S3 needs ≥3-char names → jo→jo-media). Media host ports reassigned: video 8083 (8081=taken by airflow), audio 8084 (3000=taken by a NixOS service); photopea 8487. Images: shtse8/photopea:1.0, lscr.io/linuxserver/kdenlive, lscr.io/linuxserver/audacity. OmniRoute console link uses proper URL omniroute.lab.audasmedia.com.au.

Audio / GPU follow-ups (2026-08-25)

  • Zrythm DAW: install NATIVELY on NixOS via pkgs.zrythm (no docker/webtop — no apt/AppImage). Access via RustDesk (RustDesk server already runs on .35: hbbs/hbbr). DAW audio latency over remote is ok for composing, not live multitrack recording.
  • AMD RX 6600 being added to .13: configure amdgpu driver in NixOS so containers/ML can use it (MuScriptor/Basic Pitch/vision speedup). Currently .13 has no working NVIDIA/AMD driver or container runtime (nvidia-smi fails; docker only has runc).