Files
hobbs-iac/docs/plans/2026-03-08-hf-pdocker-01-rebuild.md
jeremy de1d9e1d93 infra: full IaC state after hf-pdocker-01 rebuild (2026-03-08)
Replaces initial Nomad/Consul/Terraform skeleton with current Docker-based
infrastructure across all three nodes (hf-pdocker-01, hf-pdocker-02, bart).

Key changes:
- CLAUDE.md: updated service distribution reflecting hf-pdocker-01 restored
- docs/plans/2026-03-08-hf-pdocker-01-rebuild.md: new rebuild plan doc
- compose/bart/: ai-agents, guacamole, matrix, media, openvas, smarthome, watchtower
- compose/hf-pdocker-02/: traefik, monitoring, adguard, gitea, semaphore, wikijs,
  unifi, vaultwarden, actual-budget, mcpo, netclaw, trivy, watchtower, n8n
- compose/hf-pdocker-01/: frigate, frigate-notify, farm-agent
- stacks/: all Swarm stack definitions (monitoring, traefik, smarthome, matrix,
  guacamole, media, ai-agents, frigate, gitea, semaphore, wikijs, unifi, etc.)
- .gitignore: exclude .env credential files and acme.json certs
- .env.example: placeholder credential files for all services
- .claude/agents/: gitea-backup and other infrastructure agent configs
- scripts/: frigate media cleanup and NAS sync scripts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 18:51:25 -05:00

429 lines
12 KiB
Markdown

# hf-pdocker-01 Rebuild — Phase 1 Implementation Plan
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
**Goal:** Rebuild hf-pdocker-01 from fresh Ubuntu 24.04 to a fully operational Swarm manager with Frigate NVR, Farm Agent, and Frigate-Notify v2.
**Architecture:** Fresh Ubuntu 24.04 on NVMe, Docker CE, NFS-backed storage from Synology NAS, 5TB USB disk for Frigate recordings. Docker Swarm re-initialized as single manager with hf-pdocker-02 and bart rejoined as workers. Services deployed via Compose files already on NAS.
**Tech Stack:** Ubuntu 24.04, Docker CE, Docker Swarm, NFS v3, Intel VA-API/OpenVINO, Python 3.12 (containers)
**Access:** SSH to hf-pdocker-01 (192.168.86.192), user `glyptic`, password `&Rip8a115`
**Important:** All tasks execute via SSH from the WSL environment. Use the `docker-swarm-ops` agent for all remote operations.
---
### Task 1: Install System Prerequisites
**Target:** hf-pdocker-01 (192.168.86.192)
**Step 1: Install base packages**
```bash
sudo apt-get update
sudo apt-get install -y nfs-common curl jq git rsync
```
**Step 2: Install Docker CE**
```bash
# Add Docker GPG key and repo
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
```
**Step 3: Add glyptic to docker group**
```bash
sudo usermod -aG docker glyptic
```
**Step 4: Install Intel VA-API drivers for Frigate OpenVINO**
```bash
sudo apt-get install -y intel-media-va-driver-non-free vainfo
```
**Step 5: Verify**
```bash
docker --version # Expect: Docker version 28.x
docker compose version # Expect: Docker Compose version v2.x
vainfo # Expect: VA-API device listed (iHD driver, HD 630)
ls /dev/dri/ # Expect: card0, renderD128
```
---
### Task 2: Configure System Settings
**Target:** hf-pdocker-01 (192.168.86.192)
**Step 1: Set vm.swappiness to 10 (cluster standard)**
```bash
echo "vm.swappiness=10" | sudo tee -a /etc/sysctl.conf
sudo sysctl vm.swappiness=10
```
**Step 2: Verify**
```bash
sysctl vm.swappiness # Expect: vm.swappiness = 10
```
---
### Task 3: Configure NFS Mounts
**Target:** hf-pdocker-01 (192.168.86.192)
**Step 1: Create mount points**
```bash
sudo mkdir -p /mnt/docker-data /mnt/infrastructure
```
**Step 2: Add NFS entries to fstab**
```bash
echo '192.168.86.30:/volume1/Docker /mnt/docker-data nfs rw,soft,timeo=300,intr,_netdev,nfsvers=3 0 0' | sudo tee -a /etc/fstab
echo '192.168.86.30:/volume1/Infrastructure /mnt/infrastructure nfs rw,hard,intr,_netdev 0 0' | sudo tee -a /etc/fstab
```
**Step 3: Mount and verify**
```bash
sudo mount -a
ls /mnt/docker-data/configs/ # Expect: frigate, frigate-notify, etc.
ls /mnt/infrastructure/margaret/ # Expect: openclaw.json, credentials/, etc.
```
---
### Task 4: Mount 5TB Frigate Recordings Disk
**Target:** hf-pdocker-01 (192.168.86.192)
**Step 1: Identify the disk and verify existing data**
```bash
sudo blkid /dev/sda1 # Check filesystem type (expect ext4)
sudo mkdir -p /mnt/frigate-recordings
sudo mount /dev/sda1 /mnt/frigate-recordings
ls /mnt/frigate-recordings/ # Expect: frigate recording directories
```
**Step 2: Add to fstab using UUID for reliability**
```bash
# Get UUID
UUID=$(sudo blkid -s UUID -o value /dev/sda1)
echo "UUID=$UUID /mnt/frigate-recordings ext4 defaults,_netdev 0 2" | sudo tee -a /etc/fstab
```
**Step 3: Verify**
```bash
df -h /mnt/frigate-recordings # Expect: ~4.5T disk
```
---
### Task 5: Re-initialize Docker Swarm
**Target:** hf-pdocker-01 (192.168.86.192), then hf-pdocker-02 and bart
**Step 1: Initialize Swarm on hf-pdocker-01**
```bash
# On hf-pdocker-01:
docker swarm init --advertise-addr 192.168.86.192
```
Save the worker join token from the output.
**Step 2: Clean up stale Swarm state on workers**
```bash
# On hf-pdocker-02 (192.168.86.100):
docker swarm leave --force
# On bart (192.168.86.167):
docker swarm leave --force
```
**Step 3: Rejoin workers**
```bash
# On hf-pdocker-02:
docker swarm join --token <WORKER_TOKEN> 192.168.86.192:2377
# On bart:
docker swarm join --token <WORKER_TOKEN> 192.168.86.192:2377
```
**Step 4: Verify cluster**
```bash
# On hf-pdocker-01:
docker node ls # Expect: 3 nodes, hf-pdocker-01 as Leader/Manager, others as Workers
```
**Step 5: Recreate overlay networks**
```bash
# On hf-pdocker-01:
docker network create --driver overlay --attachable traefik-public
```
---
### Task 6: Deploy Frigate NVR
**Target:** hf-pdocker-01 (192.168.86.192)
**Step 1: Update Frigate config MQTT address**
The Frigate config at `/mnt/docker-data/configs/frigate/config/config.yml` has MQTT pointed at `192.168.86.192:1883` (the old hf-pdocker-01 address). Mosquitto is currently running on bart (192.168.86.167) as a failover service.
```bash
# On hf-pdocker-01, edit the config to point MQTT to bart:
sed -i 's/host: 192.168.86.192/host: 192.168.86.167/' /mnt/docker-data/configs/frigate/config/config.yml
```
Verify the change:
```bash
grep -A2 "^mqtt:" /mnt/docker-data/configs/frigate/config/config.yml
# Expect: host: 192.168.86.167
```
**Step 2: Deploy Frigate**
```bash
cd /mnt/docker-data/compose/hf-pdocker-01/frigate
docker compose up -d
```
**Step 3: Verify**
```bash
docker ps --filter name=frigate --format "table {{.Names}}\t{{.Status}}" # Expect: Up
curl -s http://localhost:5000/api/version # Expect: Frigate version response
curl -s http://localhost:5000/api/stats | jq '.detectors' # Expect: openvino detector ~10ms inference
```
Wait 1-2 minutes for cameras to initialize, then check:
```bash
curl -s http://localhost:5000/api/stats | jq '.cameras | keys' # Expect: list of camera names
```
---
### Task 7: Deploy Farm Agent
**Target:** hf-pdocker-01 (192.168.86.192)
The existing farm-agent compose references `127.0.0.1:5050` (local registry, which is gone). We'll build the image directly from Gitea instead.
**Step 1: Clone farm-manager repo and build agent image**
```bash
cd /tmp
git clone http://192.168.86.100:3003/jeremy/farm-manager.git
cd farm-manager/agent
docker build -t farm-agent:latest .
```
**Step 2: Update compose file to use local image**
```bash
# Edit the compose file on NAS
sed -i 's|image: 127.0.0.1:5050/farm-agent:latest|image: farm-agent:latest|' /mnt/docker-data/compose/hf-pdocker-01/farm-agent/docker-compose.yml
```
**Step 3: Deploy**
```bash
cd /mnt/docker-data/compose/hf-pdocker-01/farm-agent
docker compose up -d
```
**Step 4: Verify**
```bash
docker ps --filter name=farm-agent --format "table {{.Names}}\t{{.Status}}"
curl -s http://localhost:8889/health # Expect: healthy response
```
---
### Task 8: Deploy Frigate-Notify v2
**Target:** hf-pdocker-01 (192.168.86.192)
**Step 1: Clone frigate-notify repo**
```bash
cd /tmp
git clone http://192.168.86.100:3003/jeremy/frigate-notify.git
```
**Step 2: Build the image**
```bash
cd /tmp/frigate-notify
docker build -t frigate-notify:latest .
```
**Step 3: Create .env file with secrets**
The compose file needs `ANTHROPIC_API_KEY`, `MATRIX_ACCESS_TOKEN`, and `MATRIX_ROOM_ID`. Retrieve these from Vaultwarden or use known values.
Known values from MEMORY.md:
- `MATRIX_ACCESS_TOKEN`: `syt_ZnJpZ2F0ZQ_uaKUheedpkQBqtCaldsa_2ifSTC` (bot: @frigate:hobbs.farm)
- `MATRIX_ROOM_ID`: `!MTsFCQjnmLUNFGJePz:hobbs.farm`
- `ANTHROPIC_API_KEY`: retrieve from vault or from bart's ai-agents .env
```bash
cat > /mnt/docker-data/compose/hf-pdocker-01/frigate-notify/.env << 'EOF'
ANTHROPIC_API_KEY=<retrieve from vault>
MATRIX_ACCESS_TOKEN=syt_ZnJpZ2F0ZQ_uaKUheedpkQBqtCaldsa_2ifSTC
MATRIX_ROOM_ID=!MTsFCQjnmLUNFGJePz:hobbs.farm
EOF
```
**Step 4: Update compose to use built image instead of build context, and fix IPs**
The compose file on NAS references `build: context: .` which won't work from NAS path. Update to use the locally built image. Also update MQTT and Matrix homeserver IPs since those services are on bart now.
Updated compose should have:
- `image: frigate-notify:latest` (instead of `build:`)
- `FRIGATE_URL=http://localhost:5000` (Frigate is now local on same host)
- `MQTT_HOST=192.168.86.167` (Mosquitto on bart)
- `MATRIX_HOMESERVER=http://192.168.86.167:8008` (Synapse on bart)
**Step 5: Deploy**
```bash
cd /mnt/docker-data/compose/hf-pdocker-01/frigate-notify
docker compose up -d
```
**Step 6: Verify**
```bash
docker ps --filter name=frigate-notify --format "table {{.Names}}\t{{.Status}}"
curl -s http://localhost:5199/health # Expect: healthy
```
---
### Task 9: Restore Cron Jobs
**Target:** hf-pdocker-01 (192.168.86.192)
**Step 1: Verify scripts are accessible on NAS**
```bash
ls -la /mnt/docker-data/scripts/sync-frigate-to-nas.sh
ls -la /mnt/docker-data/scripts/cleanup-frigate-media.sh
cat /mnt/docker-data/scripts/sync-frigate-to-nas.sh
cat /mnt/docker-data/scripts/cleanup-frigate-media.sh
```
**Step 2: Make scripts executable**
```bash
chmod +x /mnt/docker-data/scripts/sync-frigate-to-nas.sh
chmod +x /mnt/docker-data/scripts/cleanup-frigate-media.sh
```
**Step 3: Install crontab entries**
```bash
(crontab -l 2>/dev/null; echo "0 2 * * * /mnt/docker-data/scripts/sync-frigate-to-nas.sh") | crontab -
(crontab -l 2>/dev/null; echo "0 3 * * 0 /mnt/docker-data/scripts/cleanup-frigate-media.sh") | crontab -
```
**Step 4: Verify**
```bash
crontab -l # Expect: both cron entries listed
```
---
### Task 10: Monitoring Integration
**Target:** hf-pdocker-01 + hf-pdocker-02 (Prometheus)
**Step 1: Deploy Swarm global services (Telegraf + Node-exporter)**
On hf-pdocker-01, deploy the monitoring stacks that run globally:
```bash
# Check if the stack files exist on NAS
ls /mnt/docker-data/compose/hf-pdocker-01/ # Look for telegraf, node-exporter stacks
```
If Telegraf and Node-exporter were Swarm stacks, redeploy them:
```bash
# These were global swarm services - redeploy the stacks
docker stack deploy -c /path/to/telegraf-stack.yml telegraf
docker stack deploy -c /path/to/node-exporter-stack.yml node-exporter
```
**Step 2: Update Prometheus blackbox targets**
On hf-pdocker-02 (192.168.86.100), ensure Prometheus has blackbox probe targets for the new services:
Targets to verify/add:
- `http://192.168.86.192:5000` (Frigate)
- `http://192.168.86.192:5199/health` (Frigate-Notify)
- `http://192.168.86.192:8889/health` (Farm Agent)
**Step 3: Hot-reload Prometheus**
```bash
# On hf-pdocker-02:
curl -X POST http://localhost:9095/-/reload
```
**Step 4: Verify in Grafana**
Check Grafana at http://192.168.86.100:3001 — verify the new targets show as UP in the Prometheus targets page.
---
## Phase 1 Complete Checklist
After all tasks, verify:
- [ ] Docker running on hf-pdocker-01
- [ ] NFS mount at /mnt/docker-data working
- [ ] 5TB disk mounted at /mnt/frigate-recordings
- [ ] Swarm cluster: 3 nodes (1 manager + 2 workers)
- [ ] Frigate running, cameras streaming, OpenVINO detector working
- [ ] Farm Agent responding on :8889
- [ ] Frigate-Notify v2 healthy on :5199
- [ ] Cron jobs installed for sync + cleanup
- [ ] Prometheus monitoring all new endpoints
- [ ] All blackbox probes green
## Phase 2 (Future)
Migrate failover services back to hf-pdocker-01:
- Traefik (from hf-pdocker-02)
- Monitoring stack (from hf-pdocker-02)
- AdGuard Home (from hf-pdocker-02)
- Home Assistant, ESPHome, Mosquitto (from bart)
- Matrix/Synapse (from bart)
- Guacamole (from bart)
- AI Agents (from bart)
- Farm Manager API (new deploy)