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:
@@ -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"
|
||||
Reference in New Issue
Block a user