--- created: 2026-08-21 20:08 modified: 2026-08-24 09:39 type: note tags: - ai - family - homelab aliases: [] --- # [[# DeepSeek Harness (dsh) Home Lab Setup]] > **IMPLEMENTATION BRIEF for the dsh agent (updated by family-home-lab parent project).** > The dsh agent builds these instances. The **parent console** (FastAPI portal at `console.lab.audasmedia.com.au`) is built separately and provides login, session routing and tool launching. Read this whole note before deploying. ## 0. Context — what the parent console provides (do NOT rebuild) The family-home-lab project (`/home/sam/home_network/custom_tools/family_home_lab/plan.md` on .27) deploys on `.13`: - A FastAPI + Jinja2 + HTMX console at **`console.lab.audasmedia.com.au`** (port `8500` on .13) with per-user login (**Sam, Jo, Harry, Finn**) — bcrypt password auth, signed HTTP-only session cookies. - The console links to each user's dsh instance after they log in. - RabbitMQ + Celery workers, PostgreSQL+pgvector, Garage S3 (see [[FAMILY S3 Storage Integration & Blueprint]]). **dsh must NOT implement its own cross-user account system** — one user per container instance is correct; the console decides which instance a user sees. ## 1. Network environment (verified live) | Item | Value | |---|---| | Subnet | `192.168.20.0/24`, gateway `.1` | | dsh host | **`.13` nixos-desktop** (`sam@192.168.20.13`), NixOS, Docker host, 15.5 GB RAM | | Reverse proxy | **Caddy on `.35`** (`sam@192.168.20.35`) — already proxies `*.home.lab`. Add entries there; do NOT run a second Caddy in compose | | Local DNS | Pi-hole on `.13` — add local records → `.35` | | LLM routing | **OmniRoute already running at `.13:20129`** (API) / `:20128` (dashboard). Point dsh providers at `http://192.168.20.13:20129/v1` instead of external APIs | | Open WebUI | Being retired — dsh replaces it as the chat layer | ### Port allocation (avoid collisions — verified in use on .13) In-use: 53, 1883, 3001, 3002, 4000, 5000, 5432-5434, 5678, 8079-8082, 8088, 8090-8091, 8787, 9001, 9010-9011, 9090-9091, 10200, 20128-20129, plus new family-home-lab stack starting at **8500**. **dsh instances:** use `3081` (sam), `3082` (jo), `3083` (harry), `3084` (finn). ## 2. System architecture Subdomains (not subpaths) to prevent WebSocket failures: ``` [ Caddy on .35 ] │ ┌──────────┬────────┼─────────┬──────────────┐ ▼ ▼ ▼ ▼ ▼ dsh-sam dsh-jo dsh-harry dsh-finn console.lab.audasmedia.com.au :3081 :3082 :3083 :3084 (.13:8500) ``` ## 3. Docker Compose (deploy inside `/home/sam/Docker/Containers/dsh/`) Match existing conventions: PUID/PGID 1000, restart unless-stopped. ```yaml services: dsh-sam: image: node:20-slim container_name: dsh-sam command: npx @deepseek-ai/dsh web --port 3080 ports: - "3081:3080" volumes: - /mnt/data/family-home-lab/dsh/sam/workspace:/workspace - /mnt/data/family-home-lab/dsh/sam/config:/root/.config restart: unless-stopped # repeat for jo(:3082), harry(:3084→3083), finn(:3084) ``` Data lives under `/mnt/data/family-home-lab/dsh//` so it's covered by the Borg backup job. ## 4. Caddy entries (on .35, `/etc/caddy/Caddyfile` or its compose config) ```caddy dsh-sam.lab.audasmedia.com.au { reverse_proxy 192.168.20.13:3081 } dsh-jo.lab.audasmedia.com.au { reverse_proxy 192.168.20.13:3082 } dsh-harry.lab.audasmedia.com.au { reverse_proxy 192.168.20.13:3083 } dsh-finn.lab.audasmedia.com.au { reverse_proxy 192.168.20.13:3084 } ``` **Iframe requirement (from parent console):** tools are embedded inline in the console where possible. Ensure Caddy does not add `X-Frame-Options: DENY` and that dsh sets no restrictive CSP frame-ancestors. If dsh sets headers itself, allow framing from `console.lab.audasmedia.com.au`. **Session handoff (to coordinate with console):** the console links out with a short-lived one-time token (`?token=...`) so users don't re-enter credentials; dsh should accept and exchange it, or at minimum tolerate being launched from the console. Coordinate final design with the parent project. ## 5. Hardening & customizing tools (`dsh.config.yaml`) Providers point at local OmniRoute: ```yaml providers: openai-compatible: baseUrl: "http://192.168.20.13:20129/v1" apiKey: "" plugins: - name: dsh-plugin-file-editor - name: dsh-plugin-translation - name: dsh-plugin-ocr # STRICTLY EXCLUDED for kids' instances: # - dsh-plugin-shell / persistent-bash ``` Per-user restrictions: Sam full plugins; Jo/Harry/Finn no shell/bash plugins. ## 6. Deployment checklist 1. `mkdir -p /mnt/data/family-home-lab/dsh/{sam,jo,harry,finn}/{workspace,config}` 2. Compose up from `/home/sam/Docker/Containers/dsh/` 3. ~~Pi-hole records~~ not needed — public DNS `*.lab.audasmedia.com.au` already resolves to `.35` 4. Add Caddyfile entries on .35, reload 5. Configure OmniRoute provider keys per instance 6. Verify WebSocket connectivity through Caddy 7. Notify parent project when URLs are live so console tool cards can link them