infra: hf-pdocker-01 Phase 2 migration — all services returned from failover
Node hf-pdocker-01 hardware fully repaired and rebuilt (2026-03-08). This commit captures the completed Phase 2 migration where all failover services are returned from hf-pdocker-02/bart back to hf-pdocker-01 as their permanent home. New compose stacks for hf-pdocker-01: - adguard: AdGuard Home DNS/ad-blocking (:3000, :53) - traefik: Reverse proxy with TLS (:80/:443/:8090), .env.example included - monitoring: Grafana, Prometheus, Alertmanager, InfluxDB, Blackbox, matrix-receiver - smarthome: Home Assistant (:8123), ESPHome (:6052), Mosquitto (:1883/:8883) - matrix: Synapse homeserver (:8008) + synapse-db + well-known (:8010) - guacamole: Guacamole (:8199) + guacd + guacamole-db (local MySQL) - farm-manager: Farm Manager API (:8888) Updated compose stacks for hf-pdocker-01: - frigate-notify: MQTT/Matrix hosts reverted from bart (.167) to hf-pdocker-01 (.192) Documentation: - docs/plans/2026-03-08-hf-pdocker-01-phase2-migration.md (new) - CLAUDE.md: Full service distribution update — failover labels removed, hf-pdocker-02/bart cleaned up to reflect only permanent services, NetClaw/Aaron added to hf-pdocker-02, DNSStubListener fix noted Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -10,7 +10,7 @@ This repository manages a **homelab infrastructure** with self-hosted services r
|
||||
|
||||
**Nodes:**
|
||||
- **hf-pdocker-01** (192.168.86.192) - Swarm Manager, core infrastructure + Frigate NVR - **RESTORED (2026-03-08)**
|
||||
- **hf-pdocker-02** (192.168.86.100) - Standalone Compose services (dev tools, utilities) + **FAILOVER: Traefik, Monitoring, AdGuard**
|
||||
- **hf-pdocker-02** (192.168.86.100) - Standalone Compose services (dev tools, utilities)
|
||||
- **bart** (192.168.86.167) - Standalone Compose services (media stack, OpenVAS)
|
||||
|
||||
**Synology NAS** (192.168.86.30) - Centralized NFS storage for all service data
|
||||
@@ -23,53 +23,39 @@ This repository manages a **homelab infrastructure** with self-hosted services r
|
||||
hf-pdocker-01 (Manager, 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] Home Assistant (:8123) -- MIGRATED BACK 2026-03-08
|
||||
├── [COMPOSE] ESPHome (:6052) -- MIGRATED BACK 2026-03-08
|
||||
├── [COMPOSE] Mosquitto (:1883, :8883) -- MIGRATED BACK 2026-03-08
|
||||
├── [COMPOSE] Farm Agent (:8889) -- image built locally from Gitea
|
||||
├── [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:18791, clippy:18792, bob:18800)
|
||||
├── [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)
|
||||
├── [SWARM] Telegraf (global), Node-exporter (global)
|
||||
├── [CRON] sync-frigate-to-nas (daily 2am), cleanup-frigate-media (weekly Sun 3am)
|
||||
├── 5TB USB disk at /mnt/frigate-recordings (Frigate recordings storage)
|
||||
[Failover services remain on hf-pdocker-02/bart until Phase 2]
|
||||
|
||||
bart (Worker, 15GB RAM, i5-4570T, HDD) -- ALSO HOSTING FAILOVER SERVICES
|
||||
bart (Worker, 15GB RAM, i5-4570T, HDD)
|
||||
├── [COMPOSE] Media Stack (Jellyfin, Sonarr, Radarr, SABnzbd, NZBHydra2, Jellyseerr)
|
||||
├── [COMPOSE] OpenVAS (vulnerability scanner)
|
||||
├── [COMPOSE] Farm Agent (:8889)
|
||||
├── [COMPOSE] Watchtower
|
||||
├── [SWARM] Telegraf (global), Node-exporter (global)
|
||||
├── [COMPOSE] Synapse/Matrix (:8008) + synapse-db (postgres) + wellknown (:8010) -- FAILOVER from hf-pdocker-01
|
||||
├── [COMPOSE] Guacamole (:8199) + guacd + guacamole-db (mysql, LOCAL /var/lib/guacamole-db) -- FAILOVER from hf-pdocker-01
|
||||
├── [COMPOSE] AI Agents (margaret, spirit, bob, clippy) -- FAILOVER from hf-pdocker-01 (2026-03-07)
|
||||
|
||||
hf-pdocker-02 (Worker, 7.6GB RAM, i7-6700T, HDD) -- PRIMARY NODE DURING FAILOVER
|
||||
├── [COMPOSE] Traefik (reverse proxy, ports 80/443/8090) -- FAILOVER from hf-pdocker-01
|
||||
├── [COMPOSE] Monitoring (Grafana :3001, Prometheus :9095, Alertmanager :9093, InfluxDB :8086, Blackbox :9115, matrix-receiver :9094) -- FAILOVER
|
||||
├── [COMPOSE] AdGuard Home (:3000, :53) -- FAILOVER
|
||||
hf-pdocker-02 (Worker, 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] NetClaw/Aaron (:1179) -- AI network agent
|
||||
├── [COMPOSE] Farm Agent (:8889)
|
||||
├── [COMPOSE] Watchtower
|
||||
├── [SWARM] Telegraf (global), Node-exporter (global), Portainer
|
||||
├── [SWARM] Telegraf (global), Node-exporter (global)
|
||||
|
||||
Services restored to hf-pdocker-01 (post-recovery):
|
||||
- Frigate NVR (:5000) -- back on hf-pdocker-01 with GPU
|
||||
- Frigate-Notify v2 (:5199) -- deployed 2026-03-08
|
||||
- Farm Agent (:8889)
|
||||
- Mosquitto MQTT (:1883, :8883) -- migrated back 2026-03-08
|
||||
- Home Assistant (:8123) -- migrated back 2026-03-08
|
||||
- ESPHome (:6052) -- migrated back 2026-03-08
|
||||
Services still on failover nodes (not yet returned):
|
||||
- Matrix/Synapse -- still on bart
|
||||
- Guacamole -- still on bart
|
||||
- AI Agents -- still on bart
|
||||
- Traefik -- still on hf-pdocker-02
|
||||
- Monitoring stack -- still on hf-pdocker-02
|
||||
- AdGuard Home -- still on hf-pdocker-02
|
||||
- Farm Manager API (not yet migrated back)
|
||||
```
|
||||
|
||||
## Working with This Repository
|
||||
@@ -91,8 +77,8 @@ All service data lives on the **Synology NAS** via NFS, mounted at `/mnt/docker-
|
||||
├── media/ # Frigate recordings
|
||||
├── traefik/ # Let's Encrypt certs
|
||||
└── compose/ # Standalone compose files per node
|
||||
├── hf-pdocker-01/{frigate,frigate-notify}/
|
||||
├── hf-pdocker-02/{unifi,gitea,semaphore,wikijs,vaultwarden,actual-budget,mcpo,trivy,watchtower}/
|
||||
├── hf-pdocker-01/{frigate,frigate-notify,matrix,smarthome,guacamole,ai-agents,traefik,adguard}/
|
||||
├── hf-pdocker-02/{unifi,gitea,semaphore,wikijs,vaultwarden,actual-budget,mcpo,trivy,netclaw,watchtower}/
|
||||
└── bart/{media,openvas,watchtower}/
|
||||
```
|
||||
|
||||
@@ -163,9 +149,18 @@ compose/ # Standalone Compose definitions (deployed per-node)
|
||||
- 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
|
||||
- AdGuard: :3000
|
||||
- Traefik Dashboard: :8090
|
||||
- Prometheus: :9095
|
||||
- Alertmanager: :9093
|
||||
- InfluxDB: :8086
|
||||
- Blackbox Exporter: :9115
|
||||
- matrix-alertmanager-receiver: :9094
|
||||
- AI Agents (margaret :18790, spirit :18791, clippy :18792, bob :18800) -- loopback only
|
||||
- Farm Manager: :8888 (dashboard + API)
|
||||
- Farm Agent: :8889
|
||||
|
||||
@@ -179,6 +174,7 @@ compose/ # Standalone Compose definitions (deployed per-node)
|
||||
- Actual Budget: :5006
|
||||
- MCPO: :8001
|
||||
- Trivy: :4954
|
||||
- NetClaw/Aaron: :1179 (internal only)
|
||||
|
||||
**bart (192.168.86.167):**
|
||||
- Farm Agent: :8889
|
||||
@@ -189,7 +185,6 @@ compose/ # Standalone Compose definitions (deployed per-node)
|
||||
- NZBHydra2: :5076
|
||||
- Jellyseerr: :5055
|
||||
- OpenVAS: :9392
|
||||
- AI Agents (margaret :18790, spirit :18791, clippy :18792, bob :18800) -- loopback only, failover from hf-pdocker-01
|
||||
|
||||
**GPU Machine (192.168.86.196, RTX 3090):**
|
||||
- Ollama: :11434 (vision LLM, llava:13b)
|
||||
@@ -305,3 +300,4 @@ All persistent data on NAS at `/mnt/docker-data/`:
|
||||
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.
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
services:
|
||||
adguardhome:
|
||||
image: adguard/adguardhome:latest
|
||||
container_name: adguardhome
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- /mnt/docker-data/configs/adguardhome/work:/opt/adguardhome/work
|
||||
- /mnt/docker-data/configs/adguardhome/conf:/opt/adguardhome/conf
|
||||
ports:
|
||||
- "53:53/tcp"
|
||||
- "53:53/udp"
|
||||
- "3000:3000/tcp"
|
||||
- "853:853/tcp"
|
||||
mem_limit: 256M
|
||||
memswap_limit: 256M
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -q --spider http://localhost:3000/ || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
@@ -0,0 +1,25 @@
|
||||
services:
|
||||
farm-manager:
|
||||
image: farm-manager:latest
|
||||
container_name: farm-manager
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8888:8888"
|
||||
environment:
|
||||
- CONFIG_PATH=/app/config.json
|
||||
- GROUPS_PATH=/data/groups.json
|
||||
volumes:
|
||||
- /mnt/docker-data/configs/farm-manager:/data
|
||||
mem_limit: 256M
|
||||
memswap_limit: 256M
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -sf http://localhost:8888/health || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 15s
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
@@ -9,9 +9,9 @@ services:
|
||||
environment:
|
||||
- TZ=America/Chicago
|
||||
- FRIGATE_URL=http://localhost:5000
|
||||
- MQTT_HOST=192.168.86.167
|
||||
- MQTT_HOST=192.168.86.192
|
||||
- MQTT_PORT=1883
|
||||
- MATRIX_HOMESERVER=http://192.168.86.167:8008
|
||||
- MATRIX_HOMESERVER=http://192.168.86.192:8008
|
||||
- CLIP_SERVICE_URL=http://192.168.86.196:5200
|
||||
- OLLAMA_URL=http://192.168.86.196:11434
|
||||
- OLLAMA_MODEL=llava:13b
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
services:
|
||||
guacamole:
|
||||
image: guacamole/guacamole:latest
|
||||
container_name: guacamole
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- GUACD_HOSTNAME=guacd
|
||||
- MYSQL_HOSTNAME=guacamole-db
|
||||
- MYSQL_DATABASE=guacamole_db
|
||||
- MYSQL_USER=guacamole_user
|
||||
- MYSQL_PASSWORD=guacamole_pass
|
||||
ports:
|
||||
- "8199:8080"
|
||||
networks:
|
||||
- guacamole-internal
|
||||
depends_on:
|
||||
guacamole-db:
|
||||
condition: service_healthy
|
||||
mem_limit: 512M
|
||||
memswap_limit: 512M
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -f http://localhost:8080/guacamole/ || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 60s
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
|
||||
guacd:
|
||||
image: guacamole/guacd:latest
|
||||
container_name: guacd
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- guacamole-internal
|
||||
mem_limit: 512M
|
||||
memswap_limit: 512M
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
|
||||
guacamole-db:
|
||||
image: mysql:8.0
|
||||
container_name: guacamole-db
|
||||
user: "1024:100"
|
||||
restart: unless-stopped
|
||||
command: --innodb-use-native-aio=0 --innodb-buffer-pool-size=128M
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=guacamole_root
|
||||
- MYSQL_DATABASE=guacamole_db
|
||||
- MYSQL_USER=guacamole_user
|
||||
- MYSQL_PASSWORD=guacamole_pass
|
||||
volumes:
|
||||
# NFS cannot be used for MySQL due to persistent NLM lock issues (ibdata1, dblwr files)
|
||||
# guacamole-db uses LOCAL storage on hf-pdocker-01
|
||||
- /var/lib/guacamole-db:/var/lib/mysql
|
||||
networks:
|
||||
- guacamole-internal
|
||||
mem_limit: 512M
|
||||
memswap_limit: 512M
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.enable=false"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "mysqladmin ping -h 127.0.0.1 --silent"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
|
||||
networks:
|
||||
guacamole-internal:
|
||||
driver: bridge
|
||||
@@ -0,0 +1,86 @@
|
||||
services:
|
||||
synapse:
|
||||
image: matrixdotorg/synapse:latest
|
||||
container_name: synapse
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- SYNAPSE_SERVER_NAME=mess.hobbs.farm
|
||||
- SYNAPSE_REPORT_STATS=no
|
||||
volumes:
|
||||
- /mnt/docker-data/configs/matrix/data:/data
|
||||
ports:
|
||||
- "8008:8008"
|
||||
networks:
|
||||
- matrix-internal
|
||||
depends_on:
|
||||
synapse-db:
|
||||
condition: service_healthy
|
||||
mem_limit: 1G
|
||||
memswap_limit: 1G
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -fSs http://localhost:8008/health || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 60s
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
|
||||
wellknown:
|
||||
image: nginx:alpine
|
||||
container_name: matrix-wellknown
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- /mnt/docker-data/configs/matrix/wellknown:/usr/share/nginx/html/.well-known/matrix:ro
|
||||
ports:
|
||||
- "8010:80"
|
||||
mem_limit: 64M
|
||||
memswap_limit: 64M
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -q --spider http://localhost:80/ || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 15s
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
|
||||
synapse-db:
|
||||
image: postgres:15-alpine
|
||||
container_name: synapse-db
|
||||
user: "1024:100"
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- POSTGRES_USER=synapse
|
||||
- POSTGRES_PASSWORD=synapse
|
||||
- POSTGRES_DB=synapse
|
||||
- POSTGRES_INITDB_ARGS=--encoding=UTF-8 --lc-collate=C --lc-ctype=C
|
||||
volumes:
|
||||
- /mnt/docker-data/databases/matrix-db:/var/lib/postgresql/data
|
||||
networks:
|
||||
- matrix-internal
|
||||
mem_limit: 256M
|
||||
memswap_limit: 256M
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.enable=false"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U synapse -d synapse"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
|
||||
networks:
|
||||
matrix-internal:
|
||||
driver: bridge
|
||||
@@ -0,0 +1,153 @@
|
||||
networks:
|
||||
monitoring-net:
|
||||
name: monitoring-net
|
||||
|
||||
services:
|
||||
grafana:
|
||||
image: grafana/grafana:latest
|
||||
container_name: grafana
|
||||
restart: unless-stopped
|
||||
user: "104"
|
||||
networks:
|
||||
- monitoring-net
|
||||
ports:
|
||||
- "3001:3000"
|
||||
volumes:
|
||||
- /mnt/docker-data/configs/grafana:/var/lib/grafana
|
||||
mem_limit: 512M
|
||||
memswap_limit: 512M
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -q --spider http://localhost:3000/api/health || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
|
||||
prometheus:
|
||||
image: prom/prometheus:latest
|
||||
container_name: prometheus
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- monitoring-net
|
||||
ports:
|
||||
- "9095:9090"
|
||||
command:
|
||||
- '--config.file=/etc/prometheus/prometheus.yml'
|
||||
- '--storage.tsdb.path=/prometheus'
|
||||
- '--web.console.libraries=/usr/share/prometheus/console_libraries'
|
||||
- '--web.console.templates=/usr/share/prometheus/consoles'
|
||||
- '--web.enable-lifecycle'
|
||||
volumes:
|
||||
- /mnt/docker-data/configs/prometheus:/etc/prometheus
|
||||
mem_limit: 512M
|
||||
memswap_limit: 512M
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -q --spider http://localhost:9090/-/healthy || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
|
||||
alertmanager:
|
||||
image: prom/alertmanager:latest
|
||||
container_name: alertmanager
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- monitoring-net
|
||||
ports:
|
||||
- "9093:9093"
|
||||
command:
|
||||
- '--config.file=/etc/alertmanager/alertmanager.yml'
|
||||
- '--storage.path=/alertmanager'
|
||||
volumes:
|
||||
- /mnt/docker-data/configs/alertmanager:/etc/alertmanager
|
||||
- alertmanager-data:/alertmanager
|
||||
mem_limit: 256M
|
||||
memswap_limit: 256M
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -q --spider http://localhost:9093/-/healthy || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
|
||||
influxdb:
|
||||
image: influxdb:1.8-alpine
|
||||
container_name: influxdb
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- monitoring-net
|
||||
ports:
|
||||
- "8086:8086"
|
||||
volumes:
|
||||
- /mnt/docker-data/configs/influxdb:/var/lib/influxdb
|
||||
mem_limit: 1G
|
||||
memswap_limit: 1G
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -q --spider http://localhost:8086/ping || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
|
||||
matrix-alertmanager-receiver:
|
||||
image: metio/matrix-alertmanager-receiver:2026.2.25
|
||||
container_name: matrix-alertmanager-receiver
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- monitoring-net
|
||||
ports:
|
||||
- "9094:9094"
|
||||
volumes:
|
||||
- /mnt/docker-data/configs/alertmanager/matrix-receiver-config.yml:/config/config.yml:ro
|
||||
command: ["--config-path", "/config/config.yml"]
|
||||
mem_limit: 128M
|
||||
memswap_limit: 128M
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
|
||||
blackbox-exporter:
|
||||
image: prom/blackbox-exporter:latest
|
||||
container_name: blackbox-exporter
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- monitoring-net
|
||||
ports:
|
||||
- "9115:9115"
|
||||
command:
|
||||
- '--config.file=/config/blackbox.yml'
|
||||
volumes:
|
||||
- /mnt/docker-data/configs/blackbox:/config:ro
|
||||
mem_limit: 128M
|
||||
memswap_limit: 128M
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
|
||||
volumes:
|
||||
alertmanager-data:
|
||||
@@ -0,0 +1,3 @@
|
||||
# Cloudflare DNS API token for Let's Encrypt DNS challenge
|
||||
# Actual value stored in Vaultwarden as "Traefik CF_DNS_API_TOKEN"
|
||||
CF_DNS_API_TOKEN=your-cloudflare-api-token-here
|
||||
@@ -0,0 +1,39 @@
|
||||
services:
|
||||
traefik:
|
||||
image: traefik:v3.6
|
||||
container_name: traefik
|
||||
restart: unless-stopped
|
||||
command:
|
||||
- "--api.insecure=true"
|
||||
- "--providers.file.directory=/config/dynamic"
|
||||
- "--providers.file.watch=true"
|
||||
- "--entrypoints.web.address=:80"
|
||||
- "--entrypoints.websecure.address=:443"
|
||||
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
|
||||
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
|
||||
- "--certificatesresolvers.letsencrypt.acme.dnschallenge=true"
|
||||
- "--certificatesresolvers.letsencrypt.acme.dnschallenge.provider=cloudflare"
|
||||
- "--certificatesresolvers.letsencrypt.acme.email=jeremydanielhobbs@gmail.com"
|
||||
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
|
||||
environment:
|
||||
- CF_DNS_API_TOKEN=${CF_DNS_API_TOKEN}
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
- "8090:8080"
|
||||
volumes:
|
||||
- /mnt/docker-data/traefik/letsencrypt:/letsencrypt
|
||||
- /mnt/docker-data/traefik/dynamic:/config/dynamic:ro
|
||||
mem_limit: 512M
|
||||
memswap_limit: 512M
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -q --spider http://localhost:8080/api/overview || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
@@ -0,0 +1,108 @@
|
||||
# hf-pdocker-01 Phase 2 — Service Migration Back
|
||||
|
||||
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
||||
|
||||
**Goal:** Migrate all failover services back to hf-pdocker-01 from hf-pdocker-02 and bart.
|
||||
|
||||
**Architecture:** Stop services on failover nodes, start on hf-pdocker-01, update IP references and routing. Order matters due to dependencies.
|
||||
|
||||
**Dependency Chain:**
|
||||
- Mosquitto must be up before Home Assistant and Frigate MQTT config update
|
||||
- Matrix/Synapse must be up before AI Agents
|
||||
- Traefik must be up before external routing works
|
||||
- AdGuard is DNS — move carefully to minimize resolution downtime
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Migrate Mosquitto (bart → hf-pdocker-01)
|
||||
|
||||
MQTT broker — Home Assistant and Frigate depend on it.
|
||||
|
||||
1. Deploy Mosquitto on hf-pdocker-01 using compose from `/mnt/docker-data/compose/bart/smarthome/` (extract mosquitto service) or create standalone compose
|
||||
2. Verify MQTT is listening on hf-pdocker-01:1883
|
||||
3. Update Frigate config MQTT host back to 192.168.86.192 (localhost)
|
||||
4. Restart Frigate to pick up new MQTT
|
||||
5. Stop Mosquitto on bart
|
||||
|
||||
### Task 2: Migrate Home Assistant + ESPHome (bart → hf-pdocker-01)
|
||||
|
||||
Smart home services — depend on Mosquitto.
|
||||
|
||||
1. Deploy HA + ESPHome on hf-pdocker-01
|
||||
2. Update HA config: MQTT broker IP back to 192.168.86.192
|
||||
3. Verify HA web UI on :8123, ESPHome on :6052
|
||||
4. Stop HA + ESPHome on bart
|
||||
|
||||
### Task 3: Migrate Matrix/Synapse (bart → hf-pdocker-01)
|
||||
|
||||
Matrix homeserver — AI agents and alertbot depend on it.
|
||||
|
||||
1. Deploy Synapse + synapse-db + wellknown on hf-pdocker-01
|
||||
2. Verify Matrix federation and client API on :8008
|
||||
3. Update matrix-alertmanager-receiver config to point to new Synapse
|
||||
4. Stop Synapse stack on bart
|
||||
|
||||
### Task 4: Migrate Guacamole (bart → hf-pdocker-01)
|
||||
|
||||
Remote desktop gateway — has local MySQL DB on bart (NFS lock workaround).
|
||||
|
||||
1. Copy guacamole-db data from bart:/var/lib/guacamole-db to hf-pdocker-01 local storage
|
||||
2. Deploy Guacamole + guacd + guacamole-db on hf-pdocker-01
|
||||
3. Verify web UI on :8199
|
||||
4. Stop Guacamole stack on bart
|
||||
|
||||
### Task 5: Migrate AI Agents (bart → hf-pdocker-01)
|
||||
|
||||
margaret, spirit, bob, clippy — depend on Matrix/Synapse.
|
||||
|
||||
1. Build margaret-openclaw:latest image on hf-pdocker-01
|
||||
2. Update agent configs: Matrix homeserver URL back to 192.168.86.192:8008
|
||||
3. Rename Matrix account state dirs
|
||||
4. Deploy all 4 agents on hf-pdocker-01
|
||||
5. Verify Matrix connectivity
|
||||
6. Stop agents on bart
|
||||
|
||||
### Task 6: Migrate AdGuard Home (hf-pdocker-02 → hf-pdocker-01)
|
||||
|
||||
DNS server — brief downtime expected during switchover.
|
||||
|
||||
1. Deploy AdGuard on hf-pdocker-01 using NAS config
|
||||
2. Verify DNS resolution on :53 and web UI on :3000
|
||||
3. Stop AdGuard on hf-pdocker-02
|
||||
|
||||
### Task 7: Migrate Traefik (hf-pdocker-02 → hf-pdocker-01)
|
||||
|
||||
Reverse proxy — handles all external HTTPS routing.
|
||||
|
||||
1. Deploy Traefik on hf-pdocker-01 with NAS certs and dynamic configs
|
||||
2. Update dynamic configs for new service IPs (services now on .192 instead of .167)
|
||||
3. Verify HTTPS routing for mess/solo/yoda/vault/git.hobbs.farm
|
||||
4. Stop Traefik on hf-pdocker-02
|
||||
|
||||
### Task 8: Migrate Monitoring Stack (hf-pdocker-02 → hf-pdocker-01)
|
||||
|
||||
Grafana, Prometheus, Alertmanager, InfluxDB, Blackbox, matrix-receiver.
|
||||
|
||||
1. Deploy full monitoring stack on hf-pdocker-01
|
||||
2. Update Prometheus config with correct service IPs (most services now back on .192)
|
||||
3. Update Telegraf configs on all nodes to point InfluxDB to .192
|
||||
4. Verify Grafana on :3001, Prometheus on :9095
|
||||
5. Stop monitoring stack on hf-pdocker-02
|
||||
|
||||
### Task 9: Migrate Farm Manager API (new deploy on hf-pdocker-01)
|
||||
|
||||
Was never failed over — needs fresh deploy.
|
||||
|
||||
1. Clone farm-manager from Gitea, build server image
|
||||
2. Deploy Farm Manager API on :8888
|
||||
3. Update config.json with correct node IPs
|
||||
4. Verify dashboard and API
|
||||
|
||||
### Task 10: Cleanup + Final Verification
|
||||
|
||||
1. Remove stopped failover containers on bart and hf-pdocker-02
|
||||
2. Update all Prometheus blackbox targets for final service locations
|
||||
3. Hot-reload Prometheus
|
||||
4. Update Traefik dynamic configs
|
||||
5. Verify all services healthy
|
||||
6. Update CLAUDE.md, MEMORY.md, wiki
|
||||
Reference in New Issue
Block a user