795908e1ef
Standalone Compose service running a locally-built nginx image that serves a static Anthropic-API frontend. Traefik dynamic route added for public HTTPS access. Blackbox probe added to prometheus.yml for uptime monitoring. CLAUDE.md updated with service entry. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
294 lines
12 KiB
Markdown
294 lines
12 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
## Repository Overview
|
|
|
|
This repository manages a **homelab infrastructure** with self-hosted services running across 3 nodes using **standalone Docker Compose** on all nodes. (Docker Swarm was fully dismantled on 2026-04-01.)
|
|
|
|
### Cluster Architecture
|
|
|
|
**Nodes:**
|
|
- **hf-pdocker-01** (192.168.86.192) - Core infrastructure + Frigate NVR - **RESTORED (2026-03-08)**
|
|
- **hf-pdocker-02** (192.168.86.100) - Dev tools, utilities
|
|
- **bart** (192.168.86.167) - Media stack, OpenVAS
|
|
|
|
**Synology NAS** (192.168.86.30) - Centralized NFS storage for all service data
|
|
|
|
**Access:** Username `glyptic`, password `&Rip8a115` (has sudo access on all nodes)
|
|
|
|
### Service Distribution
|
|
|
|
```
|
|
hf-pdocker-01 (23GB RAM, i7-7700T, NVMe, HD 630 GPU) -- RESTORED (2026-03-08, hardware repaired)
|
|
├── [COMPOSE] Frigate NVR (:5000) -- OpenVINO GPU detector, 13 cameras active
|
|
├── [COMPOSE] Frigate-Notify v2 (:5199) -- MQTT->AI->Matrix notifications
|
|
├── [COMPOSE] clip-service (:5200) -- CLIP embeddings (ViT-L-14, CPU)
|
|
├── [COMPOSE] Home Assistant (:8123)
|
|
├── [COMPOSE] ESPHome (:6052)
|
|
├── [COMPOSE] Mosquitto (:1883, :8883)
|
|
├── [COMPOSE] Synapse/Matrix (:8008) + synapse-db (postgres) + wellknown (:8010)
|
|
├── [COMPOSE] Guacamole (:8199) + guacd + guacamole-db (mysql, LOCAL /var/lib/guacamole-db)
|
|
├── [COMPOSE] AI Agents (margaret:18790, spirit:18795 [infra ops])
|
|
├── [COMPOSE] Traefik (reverse proxy, ports 80/443/8090)
|
|
├── [COMPOSE] AdGuard Home (:3000, :53)
|
|
├── [COMPOSE] Monitoring (Grafana :3001, Prometheus :9095, Alertmanager :9093, InfluxDB :8086, Blackbox :9115, matrix-receiver :9094)
|
|
├── [COMPOSE] Farm Manager API (:8888) -- dashboard + API server
|
|
├── [COMPOSE] Farm Agent (:8889)
|
|
├── [COMPOSE] Rongorongo (:8181) -- static HTML/JS decipherment engine (Anthropic API direct from browser)
|
|
├── [REMOVED] VoiceCoach -- moved to GPU machine (192.168.86.150) 2026-04-04
|
|
├── [COMPOSE] Node-exporter (:9100) -- standalone with pid:host
|
|
├── [COMPOSE] Telegraf -- metrics collection to InfluxDB
|
|
├── [CRON] sync-frigate-to-nas (daily 2am), cleanup-frigate-media (weekly Sun 3am), restart-frigate (daily 4am)
|
|
├── 5TB USB disk at /mnt/frigate-recordings (Frigate recordings storage)
|
|
|
|
bart (15GB RAM, i5-4570T, HDD)
|
|
├── [COMPOSE] Media Stack (Jellyfin, Sonarr, Radarr, SABnzbd, NZBHydra2, Jellyseerr)
|
|
├── [COMPOSE] OpenVAS (vulnerability scanner)
|
|
├── [COMPOSE] Farm Agent (:8889)
|
|
├── [COMPOSE] Node-exporter (:9100) -- standalone with pid:host
|
|
├── [COMPOSE] Telegraf -- metrics collection to InfluxDB
|
|
├── [COMPOSE] Watchtower
|
|
|
|
hf-pdocker-02 (7.6GB RAM, i7-6700T, HDD)
|
|
├── [COMPOSE] Unifi + unifi-db (MongoDB)
|
|
├── [COMPOSE] Gitea + gitea-db (PostgreSQL)
|
|
├── [COMPOSE] Semaphore + semaphore-db (MySQL)
|
|
├── [COMPOSE] Wiki.js + wikijs-db (PostgreSQL)
|
|
├── [COMPOSE] Vaultwarden, Actual Budget, MCPO, Trivy
|
|
├── [COMPOSE] n8n + n8n-db (PostgreSQL) -- workflow automation
|
|
├── [COMPOSE] Farm Agent (:8889)
|
|
├── [COMPOSE] Node-exporter (:9100) -- standalone with pid:host
|
|
├── [COMPOSE] Telegraf -- metrics collection to InfluxDB
|
|
├── [COMPOSE] Watchtower
|
|
|
|
```
|
|
|
|
## Working with This Repository
|
|
|
|
### Environment Context
|
|
|
|
You are working in a **WSL 2 environment** on Windows. Docker is NOT directly available in WSL - all Docker operations must be performed by connecting to the remote nodes via SSH.
|
|
|
|
**Critical:** Docker is not available locally in WSL. All Docker operations must be performed by connecting to the remote nodes via SSH.
|
|
|
|
### Storage Architecture
|
|
|
|
All service data lives on the **Synology NAS** via NFS, mounted at `/mnt/docker-data` on all 3 nodes.
|
|
|
|
```
|
|
/mnt/docker-data/ (NAS: 192.168.86.30:/volume1/Docker)
|
|
├── configs/ # Application configs
|
|
├── databases/ # Database data directories
|
|
├── media/ # Frigate recordings
|
|
├── traefik/ # Let's Encrypt certs
|
|
└── compose/ # Standalone compose files per node
|
|
├── hf-pdocker-01/{frigate,frigate-notify,clip-service,matrix,smarthome,guacamole,ai-agents,traefik,adguard}/
|
|
├── hf-pdocker-02/{unifi,gitea,semaphore,wikijs,vaultwarden,actual-budget,mcpo,trivy,watchtower}/
|
|
└── bart/{media,openvas,watchtower}/
|
|
```
|
|
|
|
**NFS mount (all nodes):** `192.168.86.30:/volume1/Docker /mnt/docker-data nfs rw,soft,timeo=300,intr,_netdev,nfsvers=3 0 0`
|
|
|
|
**NFS + Databases:** Database containers on NFS require `user: "1024:100"` to avoid `chown` failures from NFS root_squash. UID 1024 is the NAS anonymous user.
|
|
|
|
### Repository File Structure
|
|
|
|
```
|
|
stacks/ # LEGACY Swarm stack definitions (Swarm dismantled 2026-04-01, kept for reference)
|
|
|
|
compose/ # Standalone Compose definitions (deployed per-node)
|
|
├── hf-pdocker-01/ # Core infrastructure + Frigate
|
|
├── hf-pdocker-02/ # Dev tools & utilities
|
|
│ ├── {service}/docker-compose.yml
|
|
│ └── {service}/.env
|
|
└── bart/ # Media stack & OpenVAS
|
|
```
|
|
|
|
### Deployment Workflow
|
|
|
|
**All services (compose/):**
|
|
1. Edit compose file in `compose/{node}/{service}/docker-compose.yml`
|
|
2. SCP to NAS path or node, then: `cd /mnt/docker-data/compose/{node}/{service} && docker compose up -d`
|
|
|
|
### Service Architecture Patterns
|
|
|
|
**Network Patterns:**
|
|
- **Compose services**: Bridge networks for service isolation
|
|
- **Public services** (Traefik): Traefik labels + dynamic config files in `/mnt/docker-data/traefik/dynamic/`
|
|
|
|
**Database Patterns:**
|
|
- PostgreSQL: `postgres:15-alpine` or `postgres:16-alpine`
|
|
- MySQL: `mysql:8.0` (Guacamole, Semaphore)
|
|
- MongoDB: `mongo:7.0` (Unifi)
|
|
- **Always** add `com.centurylinklabs.watchtower.enable=false` label
|
|
- **Always** add `user: "1024:100"` for NFS-backed database volumes
|
|
|
|
**Volume Patterns:**
|
|
- Application data: `/mnt/docker-data/configs/{service-name}/`
|
|
- Database data: `/mnt/docker-data/databases/{service-name}-db/`
|
|
- Traefik certs: `/mnt/docker-data/traefik/letsencrypt/`
|
|
|
|
## Key Services & Access
|
|
|
|
### Public Services (via Traefik on hf-pdocker-01)
|
|
|
|
- Matrix: `mess.hobbs.farm`
|
|
- Guacamole: `solo.hobbs.farm`
|
|
- Home Assistant: `yoda.hobbs.farm`
|
|
- Vaultwarden: `vault.hobbs.farm`
|
|
- Gitea: `git.hobbs.farm`
|
|
- VoiceCoach: `coach.hobbs.farm` (LiveKit WebRTC: `voice.hobbs.farm`)
|
|
- Rongorongo: `rongorongo.hobbs.farm`
|
|
|
|
### Internal Services by Node
|
|
|
|
**hf-pdocker-01 (192.168.86.192):**
|
|
- Frigate: :5000
|
|
- Frigate Alerts (v2): :5199 (web UI + REST API)
|
|
- clip-service: :5200 (CLIP embeddings, ViT-L-14, CPU)
|
|
- Home Assistant: :8123
|
|
- ESPHome: :6052
|
|
- Mosquitto: :1883
|
|
- Matrix/Synapse: :8008
|
|
- Well-known (Matrix federation): :8010
|
|
- Guacamole: :8199
|
|
- AdGuard Home: :3000 (DNS: :53)
|
|
- Traefik Dashboard: :8090 (HTTP: :80, HTTPS: :443)
|
|
- Grafana: :3001
|
|
- Prometheus: :9095
|
|
- Alertmanager: :9093
|
|
- InfluxDB: :8086
|
|
- Blackbox Exporter: :9115
|
|
- matrix-alertmanager-receiver: :9094
|
|
- AI Agents (margaret :18790, spirit :18795 [infra ops — monitors #notifications, auto-remediates alerts]) -- LAN-accessible (bind=lan, 0.0.0.0)
|
|
- Farm Manager: :8888 (dashboard + API)
|
|
- Farm Agent: :8889
|
|
- Rongorongo: :8181 (web at rongorongo.hobbs.farm)
|
|
- ~~VoiceCoach~~ -- moved to GPU machine (192.168.86.150) 2026-04-04
|
|
|
|
**hf-pdocker-02 (192.168.86.100):**
|
|
- Farm Agent: :8889
|
|
- Unifi: :8443
|
|
- Gitea: :3003 (web), :2222 (SSH)
|
|
- Semaphore: :3004
|
|
- Wiki.js: :3002
|
|
- Vaultwarden: :26226
|
|
- Actual Budget: :5006
|
|
- MCPO: :8001
|
|
- Trivy: :4954
|
|
|
|
**bart (192.168.86.167):**
|
|
- Farm Agent: :8889
|
|
- Jellyfin: :8096
|
|
- Sonarr: :8989
|
|
- Radarr: :7878
|
|
- SABnzbd: :8082
|
|
- NZBHydra2: :5076
|
|
- Jellyseerr: :5055
|
|
- OpenVAS: :9392
|
|
|
|
**GPU Machine (192.168.86.150, RTX 3090, 15GB RAM):**
|
|
- Ollama: :11434 (llama3.1:8b for VoiceCoach LLM, qwen2.5:14b, others)
|
|
- [COMPOSE] VoiceCoach (all services co-located):
|
|
- voicecoach-livekit: :7880/:7881, UDP 50000-50100 (public at voice.hobbs.farm)
|
|
- voicecoach-speaches-gpu: :8000 (GPU Whisper STT + Kokoro TTS, CUDA float16)
|
|
- voicecoach-speechbrain: :8001 (emotion analysis)
|
|
- voicecoach-token-server: :8080 (token + settings API)
|
|
- voicecoach-pipecat: pipeline agent (LLM via local Ollama llama3.1:8b)
|
|
- voicecoach-web: :8085 (public at coach.hobbs.farm)
|
|
- voicecoach-openclaw: :3100 (idle, kept for future Claude API routing)
|
|
- Compose: ~/voicecoach-speaches/docker-compose.yml
|
|
|
|
### Port Conflict Notes
|
|
|
|
Port conflicts already resolved:
|
|
- Port 8000: Freed (MCPO moved to 8001, Portainer moved elsewhere)
|
|
- Port 3000: AdGuard Home (Gitea moved to 3003)
|
|
- Port 3001: Grafana (Semaphore moved to 3004)
|
|
- Port 5000: Frigate uses host networking (registry container stopped)
|
|
- AI Agent ports re-spaced (2026-03-15): openclaw 2026.3.13 uses gateway+2 and gateway+3 for browser/chrome-relay. Agents spaced 5 apart: margaret=18790, spirit=18795
|
|
|
|
## Critical Configuration Preservation
|
|
|
|
### Encryption Keys & Passwords
|
|
|
|
- Semaphore: `SEMAPHORE_ACCESS_KEY_ENCRYPTION` encrypts sensitive data
|
|
- **Always** check for existing encryption keys before generating new ones
|
|
|
|
### Database Version Matching
|
|
|
|
Match the PostgreSQL/MySQL version to existing data directory format. Check logs for version mismatch errors.
|
|
|
|
## Post-Change Checklist (MANDATORY)
|
|
|
|
After ANY infrastructure change (deploy, remove, reconfigure, add service, change ports, modify Traefik routes), you MUST complete ALL of these before reporting done:
|
|
|
|
1. **CLAUDE.md** — Update service lists, ports, node assignments if changed
|
|
2. **MEMORY.md** — Add/update relevant memory entries
|
|
3. **Prometheus probes** — Add/remove blackbox targets, hot-reload Prometheus
|
|
4. **Wiki** — Launch documentation-keeper agent to update wiki pages (run in background)
|
|
|
|
Do NOT wait for the user to ask. Do NOT skip "because the change was small." Every change gets documented.
|
|
|
|
## Common Operations
|
|
|
|
### Deploy/Update a Compose Service
|
|
|
|
1. Edit `compose/{node}/{service}/docker-compose.yml`
|
|
2. SSH to the target node and run:
|
|
```bash
|
|
cd /mnt/docker-data/compose/{node}/{service}
|
|
docker compose up -d
|
|
```
|
|
|
|
### Troubleshoot
|
|
|
|
```bash
|
|
# On target node:
|
|
docker compose -f /mnt/docker-data/compose/{node}/{service}/docker-compose.yml logs --tail 100
|
|
docker ps --format "table {{.Names}}\t{{.Status}}"
|
|
```
|
|
|
|
### Check Cluster Health
|
|
|
|
```bash
|
|
# On each node:
|
|
docker ps # Local containers
|
|
```
|
|
|
|
## Data Management
|
|
|
|
### Storage
|
|
|
|
All persistent data on NAS at `/mnt/docker-data/`:
|
|
- `configs/` - Application configurations
|
|
- `databases/` - Database volumes
|
|
- `media/` - Frigate recordings
|
|
- `traefik/` - SSL certificates
|
|
|
|
### NAS Dependency
|
|
|
|
**Risk**: NAS failure = all services fail (single point of failure)
|
|
- NFS mount uses `soft,timeo=300` for graceful timeout
|
|
- Synology should have "Restart automatically after power failure" enabled
|
|
- Original data backups remain on local `/data/configs/` on hf-pdocker-01
|
|
|
|
## Specialized Agents
|
|
|
|
### vault-credential-manager
|
|
**Use for:** Storing/retrieving credentials from Vaultwarden
|
|
|
|
### documentation-keeper
|
|
**Use for:** Creating/updating documentation in Wiki.js
|
|
|
|
## Known Issues & Workarounds
|
|
|
|
1. **NFS root_squash**: Database containers need `user: "1024:100"` to avoid chown failures on NAS volumes
|
|
2. **Telegraf Docker Input**: Disabled due to Docker socket permission issues across nodes
|
|
3. **Watchtower API Version**: Requires `DOCKER_API_VERSION=1.44`
|
|
4. **InfluxDB Connection**: Telegraf may show timeout errors if InfluxDB is not running
|
|
5. **Frigate cameras**: Cameras on 192.168.44.x subnet may show RTSP timeouts (check camera network)
|
|
6. **Registry container**: Stopped on hf-pdocker-01 to free port 5000 for Frigate
|
|
7. **systemd-resolved DNSStubListener**: Must be disabled on any node running AdGuard Home (port 53 conflict). Fix: `/etc/systemd/resolved.conf.d/nostub.conf` with `DNSStubListener=no`, then `systemctl restart systemd-resolved`. Applied on hf-pdocker-01 and hf-pdocker-02.
|