Rend l'ensemble du repo agnostique de l'infra perso (paths/domaines/services paramétrés)

This commit is contained in:
jerem
2026-06-19 00:13:50 +02:00
parent 848dac9948
commit df66d33031
8 changed files with 48 additions and 34 deletions

View File

@@ -2,7 +2,7 @@
# Credentials Claude d'un login ISOLÉ dédié à Monitorink (scope user:profile requis par # Credentials Claude d'un login ISOLÉ dédié à Monitorink (scope user:profile requis par
# /usage -> login complet obligatoire, `claude setup-token` ne suffit PAS). # /usage -> login complet obligatoire, `claude setup-token` ne suffit PAS).
# Créer via : CLAUDE_CONFIG_DIR=/home/jerem/.monitorink-claude claude auth login # Créer via : CLAUDE_CONFIG_DIR=$HOME/.monitorink-claude claude auth login
# Le backend lit/écrit ce fichier (refresh) ; il est monté dans le conteneur sur /creds. # Le backend lit/écrit ce fichier (refresh) ; il est monté dans le conteneur sur /creds.
MONITORINK_CLAUDE_CREDS=/creds/.credentials.json MONITORINK_CLAUDE_CREDS=/creds/.credentials.json
# User-Agent attendu par l'endpoint /usage (doit ressembler à claude-code/<version>) # User-Agent attendu par l'endpoint /usage (doit ressembler à claude-code/<version>)
@@ -35,13 +35,17 @@ MONITORINK_USAGE_TTL=120
MONITORINK_LAT=48.8566 MONITORINK_LAT=48.8566
MONITORINK_LON=2.3522 MONITORINK_LON=2.3522
# NAS (optionnel) — endpoint /api/status du moniteur maison nas_monitor. # NAS (optionnel) — endpoint HTTP exposant l'état du NAS au format /api/status (moniteur
# Laisser vide pour masquer la section NAS. Depuis le conteneur, viser l'IP LAN du host. # maison ou équivalent). Laisser vide pour masquer la section NAS. Depuis le conteneur,
MONITORINK_NAS_URL=http://192.168.0.43:8766/api/status # viser l'IP LAN du host.
MONITORINK_NAS_URL=http://nas.local:8766/api/status
# Codex (optionnel) — usage ChatGPT/Codex via wham/usage. Token lu dans le auth.json de # Codex (optionnel) — usage ChatGPT/Codex via l'endpoint backend-api/usage. Le token
# Hermes monté en lecture seule (cf. docker-compose.yml). Laisser vide pour masquer Codex. # openai-codex est lu dans un auth.json maintenu frais par un processus EXTERNE et monté
MONITORINK_CODEX_TOKEN_FILE=/hermes/auth.json # en lecture seule (cf. docker-compose.yml). Laisser vide pour masquer Codex.
# MONITORINK_CODEX_DIR = dossier hôte contenant auth.json (monté sur /codex).
MONITORINK_CODEX_DIR=$HOME/.config/codex
MONITORINK_CODEX_TOKEN_FILE=/codex/auth.json
# Trackers torrent privés (optionnel) — ratio/envoi/réception du compte, sous le NAS. # Trackers torrent privés (optionnel) — ratio/envoi/réception du compte, sous le NAS.
# Liste des clés actives, puis UN bloc par tracker. v1 : type "unit3d_nuxt" (ex. c411). # Liste des clés actives, puis UN bloc par tracker. v1 : type "unit3d_nuxt" (ex. c411).
@@ -78,3 +82,9 @@ MONITORINK_CODEX_TOKEN_FILE=/hermes/auth.json
#MONITORINK_TRACKER_YGGREBORN_USER=ton.email@exemple.com #MONITORINK_TRACKER_YGGREBORN_USER=ton.email@exemple.com
#MONITORINK_TRACKER_YGGREBORN_PASS=TonMotDePasse #MONITORINK_TRACKER_YGGREBORN_PASS=TonMotDePasse
#MONITORINK_TRACKER_TTL=1800 #MONITORINK_TRACKER_TTL=1800
# ── Déploiement (docker-compose) ─────────────────────────────────────────────
# Domaine exposé par le reverse proxy (label caddy-docker-proxy). Adapter au tien.
MONITORINK_DOMAIN=monitorink.example.com
# Nom du réseau Docker EXTERNE (déjà créé) auquel rattacher le conteneur.
MONITORINK_NETWORK=monitorink-net

View File

@@ -78,14 +78,14 @@ class Config:
weather_lat: float = field(default_factory=lambda: float(_get("MONITORINK_LAT", "48.8566"))) weather_lat: float = field(default_factory=lambda: float(_get("MONITORINK_LAT", "48.8566")))
weather_lon: float = field(default_factory=lambda: float(_get("MONITORINK_LON", "2.3522"))) weather_lon: float = field(default_factory=lambda: float(_get("MONITORINK_LON", "2.3522")))
# --- NAS (moniteur maison nas_monitor, endpoint /api/status) --- # --- NAS (endpoint HTTP exposant l'état du NAS au format /api/status) ---
nas_url: str = field(default_factory=lambda: _get("MONITORINK_NAS_URL")) nas_url: str = field(default_factory=lambda: _get("MONITORINK_NAS_URL"))
# --- Codex (usage ChatGPT/Codex via wham/usage) --- # --- Codex (usage ChatGPT/Codex via backend-api/usage) ---
# Fichier auth.json de Hermes monté en lecture seule : Hermes y maintient un token # Fichier auth.json monté en lecture seule : un processus externe y maintient un token
# openai-codex frais. Monitorink le relit à chaque rendu (aucun refresh côté Monitorink). # openai-codex frais. Monitorink le relit à chaque rendu (aucun refresh côté Monitorink).
codex_token_file: str = field( codex_token_file: str = field(
default_factory=lambda: _get("MONITORINK_CODEX_TOKEN_FILE", "/hermes/auth.json") default_factory=lambda: _get("MONITORINK_CODEX_TOKEN_FILE", "/codex/auth.json")
) )
# --- Trackers torrent privés (ratio du compte) --- # --- Trackers torrent privés (ratio du compte) ---

View File

@@ -4,8 +4,8 @@ La réponse expose `rate_limit.primary_window` (5 h) et `secondary_window` (hebd
`used_percent` + `reset_*`, soit l'équivalent du `/usage` de Claude → on en fait des `used_percent` + `reset_*`, soit l'équivalent du `/usage` de Claude → on en fait des
jauges « % restant ». jauges « % restant ».
Le token d'accès est lu dans le `auth.json` de l'agent maison Hermes (monté en lecture Le token d'accès est lu dans un `auth.json` maintenu frais par un processus externe (monté
seule), qui le maintient frais. Monitorink ne fait que le relire (aucun refresh ici). en lecture seule). Monitorink ne fait que le relire (aucun refresh ici).
""" """
from __future__ import annotations from __future__ import annotations
@@ -49,7 +49,7 @@ def _human_delay(seconds: int) -> str:
def _read_token() -> str | None: def _read_token() -> str | None:
"""Lit le token openai-codex dans le auth.json de Hermes (pool actif, sinon provider).""" """Lit le token openai-codex dans le auth.json (pool actif, sinon provider)."""
try: try:
with open(config.codex_token_file) as f: with open(config.codex_token_file) as f:
data = json.load(f) data = json.load(f)

View File

@@ -1,4 +1,4 @@
"""Statuts du NAS via le moniteur maison `nas_monitor` (`GET /api/status`). """Statuts du NAS via un moniteur HTTP exposant `GET /api/status`.
Expose : occupation des disques de données (`/mnt/*`), santé des conteneurs Docker, Expose : occupation des disques de données (`/mnt/*`), santé des conteneurs Docker,
et l'état du port forwardé entre gluetun (VPN) et qBittorrent. et l'état du port forwardé entre gluetun (VPN) et qBittorrent.

View File

@@ -5,10 +5,10 @@ Lit l'access token depuis un fichier .credentials.json (login Claude isolé) pui
/usage. Affiche la structure JSON brute (uniquement des % d'usage, aucun secret) + /usage. Affiche la structure JSON brute (uniquement des % d'usage, aucun secret) +
l'interprétation de Monitorink. Sortie partageable sans risque. l'interprétation de Monitorink. Sortie partageable sans risque.
Usage (sur le homelab, après le login isolé) : Usage (sur le serveur, après le login isolé) :
python3 dev/probe_usage.py /home/jerem/.monitorink-claude/.credentials.json python3 dev/probe_usage.py ~/.monitorink-claude/.credentials.json
ou via env : ou via env :
MONITORINK_CLAUDE_CREDS=/home/jerem/.monitorink-claude/.credentials.json python3 dev/probe_usage.py MONITORINK_CLAUDE_CREDS=~/.monitorink-claude/.credentials.json python3 dev/probe_usage.py
""" """
import json import json
import os import os

View File

@@ -5,29 +5,31 @@ services:
container_name: monitorink container_name: monitorink
restart: unless-stopped restart: unless-stopped
env_file: .env env_file: .env
# Port HTTP direct sur le LAN pour la Kobo (busybox wget, sans Caddy/TLS). # Port HTTP direct sur le LAN pour la Kobo (busybox wget, sans reverse proxy/TLS).
ports: ports:
- "8899:8080" - "8899:8080"
volumes: volumes:
# Login Claude ISOLÉ dédié à Monitorink (lecture/écriture pour le refresh du token). # Login Claude ISOLÉ dédié à Monitorink (lecture/écriture pour le refresh du token).
# Créé via: CLAUDE_CONFIG_DIR=/home/jerem/.monitorink-claude claude auth login # Créé via: CLAUDE_CONFIG_DIR=$HOME/.monitorink-claude claude auth login
- /home/jerem/.monitorink-claude:/creds:rw - ${HOME}/.monitorink-claude:/creds:rw
# Token openai-codex maintenu frais par Hermes (lecture seule) -> usage Codex. # Token openai-codex maintenu frais par un processus EXTERNE (lecture seule) -> Codex.
# On monte le DOSSIER (pas le fichier) : Hermes réécrit auth.json par rename() # On monte le DOSSIER (pas le fichier) : le producteur réécrit auth.json par rename()
# atomique (nouvel inode), or un bind-mount de fichier unique reste accroché à # atomique (nouvel inode), or un bind-mount de fichier unique reste accroché à
# l'inode capturé au démarrage -> le conteneur servirait un token périmé (401). # l'inode capturé au démarrage -> le conteneur servirait un token périmé (401).
# Monter le dossier fait re-résoudre /hermes/auth.json à chaque open(). # Monter le dossier fait re-résoudre /codex/auth.json à chaque open().
- /home/jerem/.hermes:/hermes:ro # MONITORINK_CODEX_DIR = dossier hôte contenant auth.json (cf. .env).
- ${MONITORINK_CODEX_DIR:-${HOME}/.config/codex}:/codex:ro
# Cache persistant des ratios trackers (survit aux redéploiements -> pas de # Cache persistant des ratios trackers (survit aux redéploiements -> pas de
# re-login massif des 4 trackers après chaque rebuild). # re-login massif des trackers après chaque rebuild).
- /home/jerem/.monitorink-data:/data:rw - ${HOME}/.monitorink-data:/data:rw
# Optionnel : burn rate via ccusage (lecture seule des logs Claude Code principaux). # Optionnel : burn rate via ccusage (lecture seule des logs Claude Code principaux).
# Décommenter + MONITORINK_CCUSAGE=1. # Décommenter + MONITORINK_CCUSAGE=1.
# - /home/jerem/.claude/projects:/root/.claude/projects:ro # - ${HOME}/.claude/projects:/root/.claude/projects:ro
networks: networks:
- nestorr - proxy
labels: labels:
caddy: http://monitorink.homelab.nestor-server.fr # Exemple pour caddy-docker-proxy ; MONITORINK_DOMAIN défini dans .env.
caddy: http://${MONITORINK_DOMAIN:-monitorink.example.com}
caddy.reverse_proxy: "{{upstreams 8080}}" caddy.reverse_proxy: "{{upstreams 8080}}"
healthcheck: healthcheck:
test: ["CMD", "python", "-c", "import urllib.request,sys; sys.exit(0) if urllib.request.urlopen('http://localhost:8080/health').status==200 else sys.exit(1)"] test: ["CMD", "python", "-c", "import urllib.request,sys; sys.exit(0) if urllib.request.urlopen('http://localhost:8080/health').status==200 else sys.exit(1)"]
@@ -35,6 +37,8 @@ services:
timeout: 10s timeout: 10s
retries: 3 retries: 3
# Réseau du reverse proxy, déjà existant (external). Nom réel via MONITORINK_NETWORK (.env).
networks: networks:
nestorr: proxy:
external: true external: true
name: ${MONITORINK_NETWORK:-monitorink-net}

View File

@@ -13,8 +13,8 @@ BASE="/mnt/onboard/.adds/Monitorink"
LOG="$BASE/monitorink.log" LOG="$BASE/monitorink.log"
cd "$BASE" || exit 1 cd "$BASE" || exit 1
# --- Configuration --- # --- Configuration --- (adapter à l'IP/host LAN de ton serveur Monitorink)
export MONITORINK_URL="http://192.168.0.43:8899/image.png" export MONITORINK_URL="http://192.168.1.50:8899/image.png"
export MONITORINK_REFRESH=900 # PROD: refresh partiel 15 min (moins de réveils = batterie) export MONITORINK_REFRESH=900 # PROD: refresh partiel 15 min (moins de réveils = batterie)
# Cadence du full refresh : côté SERVEUR via MONITORINK_FULL_INTERVAL_MIN (défaut 120 = 2 h), # Cadence du full refresh : côté SERVEUR via MONITORINK_FULL_INTERVAL_MIN (défaut 120 = 2 h),
# indépendante du cycle. Entre deux fulls, seuls les blocs modifiés sont rafraîchis (partiel). # indépendante du cycle. Entre deux fulls, seuls les blocs modifiés sont rafraîchis (partiel).

View File

@@ -9,7 +9,7 @@
BASE="$(dirname "$0")" BASE="$(dirname "$0")"
cd "$BASE" || exit 1 cd "$BASE" || exit 1
IMAGE_URL="${MONITORINK_URL:-https://monitorink.homelab.nestor-server.fr/image.png}" IMAGE_URL="${MONITORINK_URL:-http://monitorink.local/image.png}"
# Endpoints du refresh partiel, dérivés de l'URL image (.../image.png -> .../frame.meta|frame.png). # Endpoints du refresh partiel, dérivés de l'URL image (.../image.png -> .../frame.meta|frame.png).
BASE_URL="${IMAGE_URL%/image.png}" BASE_URL="${IMAGE_URL%/image.png}"
META_URL="$BASE_URL/frame.meta" META_URL="$BASE_URL/frame.meta"