Homelab Architecture — Reference¶
Last updated: 2026-08-01
Documento canónico de la arquitectura del homelab. Aquí va lo que está vivo, no lo que está planeado. Para historia/decisiones puntuales ver el git log de este repo.
🖥 Hardware¶
Cluster Proxmox mini-pcs — 2 nodos físicos + QDevice (quórum):
| Nodo | IP | Hardware | RAM |
|---|---|---|---|
proxmox |
192.168.0.50 | AMD Ryzen 7 7735HS (8c/16t, Zen3+) + Radeon 680M iGPU | 28 GB |
proxmox2 |
192.168.0.51 | Intel Celeron N5095 (4c/4t, sin AVX2) | 8 GB |
NVMe: Kingston OM8PGP41024Q-A0 1TB en proxmox-50.
⚠️ N5095 sin AVX2: cualquier binario que requiera AVX2 (Bun, ciertos build de Node, modelos LLM nativos) falla con SIGILL. Usar variantes "baseline" siempre.
🏗 Workloads¶
VMs (en proxmox)¶
| ID | Nombre | IP | Rol |
|---|---|---|---|
| 171 | homeassistant |
192.168.0.171 | HAOS — Home Assistant 17.2.rc2 |
| 208 | ubuntu-media-server |
192.168.0.208 | Docker host (~90 containers, ~76 running — verificado 2026-08-01) |
LXCs (en proxmox, storage zfs-ha)¶
| ID | Nombre | IP | Rol |
|---|---|---|---|
| 100 | clawdbot (OpenClaw) | 192.168.0.203 | AI assistant (Telegram bot @Veraclawd_bot). VMID migró 253→100 |
| 110 | tv-gw | 192.168.0.210 | L3 gateway monitoring LG TV |
| 172 | ha-ml | 192.168.0.201 | Modelo ML arrival_predictor (HA) |
| 186 | pbs | 192.168.0.22 | Proxmox Backup Server (datastore destino) — vive en proxmox/pmx-50 |
| 251 | rag | 192.168.0.202 | RAG offline-kit + Kiwix ZIM |
| 270 | caddy-primary | 192.168.0.40 | Caddy HA MASTER (VIP keepalived .250) |
| 280 | rp-server | 192.168.0.205 | Reverse-proxy / server host |
| 281 | wp-pulse-host | 192.168.0.211 | Host WordPress Pulse |
CT 102
iarq-backup-target, LXC 101 (hermesbot), LXC 249 (beszel) y LXC 250 (kiwix) están DESTRUIDOS (confirmado 2026-08-01 víapvesh get /cluster/resources --type vm— no aparecen). Quitados de este inventario.
LXCs (en proxmox2, storage zfs-ha)¶
| ID | Nombre | IP | Rol |
|---|---|---|---|
| 123 | cloudflared | 192.168.0.207 | Cloudflare Tunnel |
| 155 | wireguard | 192.168.0.206 | VPN |
| 200 | n8n | 192.168.0.200 | Automatizaciones + alert forwarder centralizado |
| 271 | caddy-secondary | 192.168.0.41 | Caddy HA BACKUP (VIP keepalived .250) |
Otros nodos (no Proxmox)¶
| Host | IP | Rol |
|---|---|---|
pi-hole (Raspi) |
192.168.0.204 | DNS adblock (Pi-hole 6, admin :8080) |
| Terramaster NAS | 192.168.0.20 | NFS (/Volume1/backups, /Volume1/Media) |
bazzite.lan (GPU box) |
192.168.0.141 | RTX 3080 10GB, Bazzite OS (Linux). SillyTavern/koboldcpp para rol.monxas.casa, wake-on-demand + MQTT/HA (modo juego, apagado automático). Encendido manual/WoL (MAC d4:5d:64:ed:bb:d1) |
📦 Stack Docker (VM 208)¶
/home/monxas/stacks/ agrupa los compose por área:
| Stack | Compose | Highlights |
|---|---|---|
infra/ |
observabilidad + reverse proxy | Prometheus, Grafana, Loki, Promtail, blackbox-exporter, healthchecks, pihole-exporter, ntfy, dockge, dozzle, cAdvisor, node-exporter, Alertmanager, Pushgateway, homepage, uptime-kuma, unpoller |
media/ |
media stack | Jellyfin, Sonarr, Radarr, Lidarr, Prowlarr, Bazarr, Plundrio (3 containers), audiobookshelf, tunarr, metube, pinchflat, twitch-rec, FlareSolverr, jellystat, jellyfin-share |
music/ (no había fila propia antes) |
audio stack | Navidrome, Music Assistant, slskd, soularr, sonic-galaxy, shairport-sync, beets, music-reorg-ui |
tools/ |
utilities | Paperless-ngx, Immich, Karakeep, Stash, Stirling-PDF, code-server, pairdrop, ChangeDetection, Pocket-ID, ntfy, isponsorblocktv |
reverse-proxy/ |
(legacy) | ⚠️ El container Caddy fue eliminado de la VM 208 (post-F4.f). El routing vive ahora en LXC 270 caddy-primary + LXC 271 caddy-secondary tras VIP keepalived .250. Ver services-routing.md |
projects/ |
apps custom | finanzas, okrs, api-proxy, TRMNL, trip-planner, jira-tickets, justeat-tracker, justeat-menu-api, arquitectos, docs-home… (OAP vive en CT100, no en 208) |
Verificado 2026-08-01 vía
docker psen VM 208 (~90 containers totales, ~76 running en el momento del chequeo — el resto duermen vía Sablier, verservices-routing.md). Eliminados/decomisionados (perservices-routing.md, 2026-07-26):krawl,speedtest-tracker,paddleocr/ocr,markdown-tool(md/md-demo/md-api),piso,web-monitor. Esta tabla es "highlights", no exhaustiva — hay más contenedores nuevos que no estaban documentados aquí (drift acumulado, esta pasada solo corrige lo obviamente roto/borrado).Caddy expone admin en
:2019conmetricsdirective habilitada (necesario para scrape Prometheus).
📊 Observabilidad¶
Logs — Loki¶
http://192.168.0.208:3101 (puerto host es 3101, internal docker es 3100)
Hosts en Loki (9):
- proxmox-50, proxmox2-51 (vía promtail systemd /usr/local/bin/promtail v3.6.10)
- ubuntu-media-server (vía promtail container, scrape Docker socket + /var/log)
- lxc-100, lxc-123, lxc-155, lxc-186, lxc-200 (el nodo Proxmox correspondiente lee el journal de cada LXC desde /zfs-ha/subvol-<ID>-disk-0/var/log/journal)
- ha-171 (vía systemd service ha-log-pusher en proxmox-50 — websocket subscribe a system_log_event, automation_triggered, script_started, etc., push a Loki)
Retention: 30 días (limits_config.retention_period: 720h).
Desde 2026-04-25 los logs Docker de VM 208 llevan también label
host=ubuntu-media-server(antes solocontainer_name). Permite query unificada por host. Detalles + queries:../operations/logs.md.
Métricas — Prometheus¶
http://192.168.0.208:9090 (host network)
Retention: 30d / 5GB. Targets activos (38 en 23 jobs, verificado 2026-08-01 vía /api/v1/targets):
| Job | Targets | Qué |
|-----|---------|-----|
| node | 1 | localhost VM 208 |
| proxmox-nodes | 2 | pmx-50.lan, pmx-51.lan |
| cadvisor | 1 | containers VM 208 |
| caddy | 2 | caddy1.lan:2021, caddy2.lan:2021 (métricas, no el admin :2019) |
| pihole | 1 | pihole-exporter (localhost:9617 en VM 208) |
| raspi-pihole | 1 | node-exporter en el propio host Pi-hole (pihole.lan:9100) |
| homeassistant | 1 | HA ha.lan:8123 |
| ha-ml, ha-ml-node | 1 c/u | app :8000 + node-exporter :9100 en ha-ml.lan |
| n8n-node | 1 | node-exporter n8n.lan:9100 |
| tv-gw | 1 | node-exporter tv-gw.lan:9100 |
| tnas-f4423 | 1 | node-exporter NAS nas.lan:9100 |
| unifi, unifi-clients | 1 c/u | exporter UniFi (Integration API) |
| asus-router | 1 | exporter del router ASUS |
| remote-pulse-server | 1 | lxc280 (RP fleet) |
| openclaw-vm-node, openclaw-vm-process | 1 c/u | Tailscale 100.107.67.103 (Mac mini Carmelo, openclaw-vm) |
| blackbox-http-internal | 7 | Grafana, Prom, Loki /ready, cadvisor, Jellyfin LAN, HA, n8n /healthz |
| blackbox-https-external | 6 | jellyfin/sonarr/radarr/pics/ntfy/wp-pulse .monxas.casa |
| blackbox-icmp | 3 | router (.1), 8.8.8.8, 1.1.1.1 |
| pushgateway, prometheus | 1 c/u | |
Jobs nuevos desde la última pasada de docs:
asus-router,ha-ml-node,n8n-node,openclaw-vm-node/-process,raspi-pihole,remote-pulse-server,unifi/unifi-clients. El puerto decaddycambió de:2019(admin) a:2021(métricas dedicadas) en algún momento no documentado.
Dashboards Grafana¶
http://192.168.0.208:3030 — login admin / <see secrets.local.md>
Reorganizados 2026-08-01: auditoría + limpieza + fusión de dashboards solapados, 24→15 dashboards en 7 carpetas, nuevo dashboard super-panel-salud como entrada principal. Lista completa verificada vía API ese mismo día:
| Dashboard | UID | Carpeta/Emoji |
|---|---|---|
| Overview — Salud del Homelab | super-panel-salud |
🩺 Overview (nuevo, entry point) |
| Red — Router + UniFi (resumen) | red-homelab |
🌐 Red |
| Red — tv-gw (todo) | red-tv-gw-todo |
🌐 Red |
| Red — UniFi (detalle) | red-unifi-detalle |
🌐 Red |
| Red — UniFi Client Insights | jMfvAjxWz |
🌐 Red |
| Servicios — Blackbox (probes HTTP/ICMP) | xtkCtBkiz |
🐾 Servicios |
| Servicios — Caddy (completo) | servicios-caddy-completo |
🐾 Servicios |
| Servicios — Pi-hole | pihole-stats |
🐾 Servicios |
| Servicios — Remote-Pulse Fleet | remote-pulse-fleet |
🐾 Servicios |
| NAS — HyperCache (Crucial P310) | nas-hypercache |
💾 NAS |
| Logs — Overview (todos los hosts) | homelab-overview |
📜 Logs |
| Infra — Home Assistant | ha-complete-001 |
🖥️ Infra |
| Infra — Máquinas físicas | homelab-fisicos |
🖥️ Infra |
| Infra — Node Exporter (hosts) | rYdddlPWk |
🖥️ Infra |
| iarq — Stack (Carmelo VM) | iarq-stack |
🖧 iarq |
Dashboards viejos que ya NO existen (fusionados/retirados en el reorg): "Docker monitoring" (
771d9eba-...), "Logs / App" (sadlil-loki-apps-dashboard, fusionado enhomelab-overview), "Speedtest Tracker Dashboard" (el servicio se decomisionó). Tras importar dashboards comunitarios siempre arreglar: (a)datasource: None→ UID real (ef6zpdikyp0cgfProm,bf6zpf6y2cxs0eLoki); (b) defaults de template vars; (c) time range razonable.
Alertas — centralizadas via Alertmanager¶
Ver alerting-flow.md para el detalle completo (política "silencio primero": todo va callado a Vera por defecto, solo un carril reducido de alertas graves interrumpe por Telegram al instante). Resumen (recuento verificado 2026-08-01 vía API, coincide con alerting-flow.md): 20 reglas Grafana (/api/v1/provisioning/alert-rules) + 52 reglas Prometheus (alerts.yml en 7 grupos, incl. CriticalDiskUsage >90%) + 9 checks Healthchecks + OpenClaw watchdog + Morning report → convergen en Alertmanager (central, receptores telegram-grave+vera) + webhook PVE→Telegram + n8n (legacy) → Telegram @Veraclawd_bot.
💾 Backups¶
| Origen | Destino | Frecuencia | Retención |
|---|---|---|---|
| vzdump VMs (208, 171) | PBS CT 186 (pmx-50) | diario 03:00 | keep-last=7, keep-weekly=4, keep-monthly=3 |
| vzdump LXCs (123, 155) | PBS CT 186 (pmx-50) | diario 01:00 | idem |
| vzdump LXC 200 (n8n) | PBS CT 186 (pmx-50) | diario 02:00 | idem |
| vzdump LXC 281 (wp-pulse) | PBS CT 186 (pmx-50) | diario 02:00 | idem |
| vzdump LXC 100 (clawdbot) | PBS CT 186 (pmx-50) | diario 04:30 | idem |
| vzdump LXCs (270, 271, 280) | PBS CT 186 (pmx-50) | diario 05:00 | idem |
| vzdump LXCs (110, 172, 251) | PBS CT 186 (pmx-50) | diario 05:30 | idem |
| PBS verify (datastore main) | self | sábados 02:00 | outdated-after=7d |
| PBS verify (datastore archive) | self | domingos 03:00 | outdated-after=14d |
| PBS GC (garbage collect) | both datastores | diario | — |
| PBS restore test | LXC 999 temporal en zfs-ha | día 5 cada mes 04:30 | auto-destroy |
| Mirror docs git | NAS Terramaster /mnt/pve/terramaster/infra-docs/ |
diario 03:30 | git mirror, histórico |
CT 102 (iarq-backup-target) fue destruido — quitado de la fila de vzdump. El restore test (
/usr/local/bin/pbs-restore-test.shen proxmox2-51) restaura el último backup del LXC 123 (más pequeño) a un VMID temporal 999, verifica config, lo destruye. Si falla → alerta.Datastore
mainal 41% usado,archiveal 54% (verificado 2026-08-01,df -hen LXC 186). Ya no está al ~82% — ver memoriapbs_main_space_20260731.md: se recortókeep-daily3→2 y el GC liberó espacio en un ciclo posterior.
🛠 Crons centralizados (con ping a Healthchecks)¶
| Cron | Host | Schedule | Healthchecks |
|---|---|---|---|
morning-report.py |
proxmox-50 | 08:00 diario | ping 6cf57bf7-... |
mirror-homelab-repo.sh |
proxmox-50 | 03:30 diario | ping 382963b9-... |
cron.weekly/homelab-cleanup |
proxmox-50 | sáb 03:30 | ping 671596df-... |
cron.weekly/homelab-cleanup |
proxmox2-51 | sáb 03:30 | ping e6ef7611-... |
cron.weekly/homelab-cleanup |
VM 208 | sáb 03:30 | ping 66131d54-... |
pbs-restore-test.sh |
proxmox2-51 | día 5 04:30 | ping 5ebb4d84-... |
smart-collect.sh |
proxmox-50 | hourly | ping 356de4be-... |
smart-collect.sh |
proxmox2-51 | hourly | ping 6b1ce80a-... |
duck.sh (DuckDNS) |
proxmox-50 (root) | cada 15min | ping e4058286-... |
Healthchecks self-hosted en http://192.168.0.208:8073 (login [email protected] / <see secrets.local.md>). Si un cron NO hace ping en su grace window → alerta a Telegram via webhook integration.
🔐 Reverse proxy + TLS¶
Caddy vive ahora en LXCs propios (post-F4.f), ya NO en la VM 208 (el container Caddy fue eliminado):
- LXC 270 caddy-primary (.40, movido de .247, en proxmox/pmx-50) — VIP MASTER, source-of-truth del routing.
- LXC 271 caddy-secondary (.41, movido de .248, en proxmox2/pmx-51) — VIP BACKUP.
- Ambos tras el VIP keepalived .250 (VRRP). Build custom con plugins caddy-dns/cloudflare + sablierapp/sablier.
- TLS wildcard *.monxas.casa via Cloudflare DNS-01 challenge, auto-renewal ACME ARI. Admin :2019 con metrics.
- Único ingress: Cloudflare → cloudflared → VIP .250:443 → Caddy LXC 270/271 → reverse_proxy 192.168.0.208:<host_port>.
Cloudflare Tunnel en LXC 123 (cloudflared, .207, token-based via dashboard) — ingress unificados apuntando al VIP .250:443 con noTLSVerify=true + originServerName=<hostname>. Caddy hace SNI matching sobre el wildcard cert y rutea por hostname.
Sablier — middleware en Caddy que para containers idle en VM 208 y los arranca on-demand cuando llega request al hostname. 17 hostnames lazy (verificado 2026-08-01, contando bloques sablier{} en managed.caddy de LXC 270). Lista completa y cómo añadir/dormir nuevos servicios → services-routing.md.
Routing CLI: homelab-ctl.py (reemplazó tunnel-sync.py + sablier-watchdog.py; subcomandos status/sync/watch/update/smoke/remove) reconcilia labels tunnel.* + rutas estáticas de ~/scripts/tunnel-static.yaml. Ver services-routing.md.
SSO via Pocket-ID (container en VM 208, :1411, 11 clientes OIDC) — para servicios protegidos por Cloudflare Access.
🤖 OpenClaw (CT 100 clawdbot)¶
Ver openclaw-setup.md para detalles. Resumen (verificado 2026-08-01 en vivo, CT 100):
- OpenClaw 2026.7.1 (npm ls -g openclaw; doc anterior decía 2026.4.23)
- Modelo primary: anthropic/claude-sonnet-5 (vía claude-cli runtime, OAuth Claude Code subscription) — openai/gpt-5.5 es solo el último fallback en la cadena (anthropic/claude-opus-5 → claude-sonnet-4-6 → claude-opus-4-8 → gpt-5.5), NO el primary. El doc anterior tenía esto invertido (ver memoria vera_anthropic_authprofile_20260725.md: gpt-5.5 como primary era el síntoma de un perfil auth roto, no el estado normal).
- Bot Telegram: @Veraclawd_bot (token compartido con n8n forwarder y Grafana alerts)
- Gateway en 127.0.0.1:9943 (UI via nginx :9944), browser control :9945
- OAP API+frontend (port 3000/3001) — subapp de analytics
- Watchdog ACTIVO (openclaw-watchdog.timer enabled+active, verificado 2026-08-01 — contradice el estado "desactivado" que decía este doc antes; no hay evidencia de cuándo se reactivó)
🧠 GPU box — bazzite.lan (192.168.0.141)¶
Caja dedicada con GPU fuera del cluster Proxmox, no gestionada por Proxmox.
RTX 3080 10GB corriendo Bazzite OS (distro Linux gaming). Rol actual:
SillyTavern + koboldcpp para rol.monxas.casa, con integración MQTT+HA (modo
juego libera VRAM, apagado automático nocturno, wake-on-demand — entrar a
rol.monxas.casa con la máquina apagada la enciende sola vía el waker en
208:8477 + failover de Caddy). Encendido manual/WoL (MAC d4:5d:64:ed:bb:d1).
Esta sección describía antes "Casa Brain" (Windows + WSL2, Ollama :11434 +
imagegen SDXL-Turbo :9002) — ese rol no sigue vivo aquí; la máquina pasó a
Linux/Bazzite por completo. La caja Windows+WSL2 con RTX 3080 que sí sigue
activa para AI Tagger es otra máquina, en .127 (DHCP, "sobremesa").
🔑 Accesos¶
Credenciales reales en secrets.local.md (gitignored). Mapa de cuentas:
| Destino | Usuario | Variable secrets.local.md |
|---|---|---|
| proxmox-50, proxmox2-51 | root | PROXMOX_ROOT_PASS |
| ubuntu-media-server | monxas (ProxyJump via 50) | MONXAS_SSH_PASS |
| HAOS add-on SSH | hassio | HASSIO_SSH_PASS |
| Grafana | admin | GRAFANA_ADMIN_PASS |
| Healthchecks | [email protected] | (compartido |
| n8n web UI | (ver UI) | — |
| NUT UPS | monxas | NUT_MONXAS_PASS |
| Pi-hole admin | (no user) | (compartido |
| Telegram bot Veraclawd_bot | — | TELEGRAM_BOT_TOKEN |
| OpenAI API | — | OPENAI_API_KEY (sin saldo, fallback) |
| Anthropic OAuth | — | ANTHROPIC_OAUTH_TOKEN (Claude Code subscription, sin saldo) |
🧹 Cleanup automático¶
/etc/cron.weekly/homelab-cleanup en los 3 hosts (proxmox-50, proxmox2-51, VM 208):
- Borra vzdump logs huérfanos (IDs no existentes)
- find /var/log -name "*.gz|*.N" -mtime +30 -delete
- journalctl --vacuum-time=14d
- apt autoremove + autoclean
- En VM 208: docker builder prune -af, docker image prune -f, docker volume prune -f
📚 Otros docs en este directorio¶
alerting-flow.md— flow centralizado de alertas (Grafana + HC + watchdog + morning → n8n → Telegram)openclaw-setup.md— config OpenClaw (auth OAuth ChatGPT, modelo, watchdog, etc.)loki-setup-status.md— setup Loki original (legacy, verhomelab-architecture.mdpara estado actual)cloudflare-access-pocketid.md— SSO con Pocket-IDlog-rotation-config.md— rotación de logs Docker/systemdsecurity-monitoring.md— fail2bansecrets.example.md/secrets.local.md— credenciales (template + reales)scripts/— docs de scripts (jellyfin-wake, tunnel-sync, cleanup-rejected)services/systemd.mdsecurity/— firewall UFWstacks/— docs por stack (infra, media, tools)