Mettre en service le monitoring des postes (VPS, Coolify, Traefik, cron) #16

Open
opened 2026-08-15 20:11:13 +00:00 by maximus · 1 comment
Owner

Mise en service de la chaine. NON AUTOPILOT : SSH Tailscale en auth navigateur, sudo, UI Coolify et pose d'un crontab — rien de tout cela n'est une PR reversible. A executer manuellement, apres le merge de #13 et #15.

Fichiers concernes

  • test-curl.sh (modifier)
  • la-compagnie-maximus/docs/coolify-ops.md (modifier)
  • la-compagnie-maximus/docs/secret-rotation-ops.md (modifier)

Depends on

Criteres d'acceptation

  • sudo mkdir -p /data/hosts && sudo chown 1000:1000 /data/hosts sur le VPS — le conteneur tourne en uid=1000(node) et /data est root:root 755 ; sans ce chown, toute ecriture echoue en EACCES
  • Persistent Storage /data/hosts -> /data/hosts pose dans l'UI Coolify, puis confirme par docker inspect-v dans custom_docker_run_options est ignore en silence
  • Variables Coolify HOSTS_INGEST_TOKEN et HOSTS_ALLOWED_IDS=thinkpad en is_runtime=true, is_buildtime=false — le buildtime fait fuiter le secret en clair dans application_deployment_queues.logs
  • Middleware de limite de debit Traefik (~12 req/min) sur le chemin d'ingestion, meme patron que logto-admin
  • Deploiement declenche manuellement (pas d'auto-deploy : source_id=null, uuid u8000gsg044wsk0oo0w884ok)
  • Fichier ~/.config/maximus-host-agent.env (chmod 600) et copie figee de l'agent poses sur le ThinkPad, ligne */5 * * * * ajoutee au crontab
  • Deux battements consecutifs verifies via GET /hosts
  • test-curl.sh etendu aux deux nouvelles routes
  • Procedure d'ajout d'un poste consignee dans docs/coolify-ops.md
  • Rotation conjointe des deux tokens en cas de perte du portable consignee dans docs/secret-rotation-ops.md
  • Deploiement Vercel du dashboard (npx vercel --prod) une fois la-compagnie-maximus#149 mergee

Review caveats

  • ARCHITECTURE (MEDIUM) : si le mount /data/hosts est oublie, les fichiers vivent dans la couche du conteneur et disparaissent a chaque deploiement. Symptome trompeur : « les postes se vident tout seuls de temps en temps ». D'ou la verification par docker inspect.
  • SECURITE (CRITIQUE, corrige en spec) : le ThinkPad porte DEJA HEALTH_TOKEN en clair dans defenseurs/.env pour le cron defenseur-auto. Sa perte compromet les deux tokens, qui doivent etre tournes ensemble — la separation des tokens ne protege pas ce poste-la.

Decisions prises en planification

  • Issue volontairement exclue du milestone planned-* : le triage autopilot-safety ecarte les ops VPS (auth navigateur) et les actions non reversibles.

Spec source

la-compagnie-maximus/spec-plan-monitoring-postes.md + spec-decisions-monitoring-postes.md (Issue 6)

Mise en service de la chaine. NON AUTOPILOT : SSH Tailscale en auth navigateur, `sudo`, UI Coolify et pose d'un crontab — rien de tout cela n'est une PR reversible. A executer manuellement, apres le merge de #13 et #15. ## Fichiers concernes - `test-curl.sh` (modifier) - `la-compagnie-maximus/docs/coolify-ops.md` (modifier) - `la-compagnie-maximus/docs/secret-rotation-ops.md` (modifier) ## Depends on - #13, #15 (merges) ## Criteres d'acceptation - [ ] `sudo mkdir -p /data/hosts && sudo chown 1000:1000 /data/hosts` sur le VPS — le conteneur tourne en `uid=1000(node)` et `/data` est `root:root 755` ; sans ce chown, toute ecriture echoue en EACCES - [ ] Persistent Storage `/data/hosts` -> `/data/hosts` pose dans l'UI Coolify, puis confirme par `docker inspect` — `-v` dans `custom_docker_run_options` est ignore en silence - [ ] Variables Coolify `HOSTS_INGEST_TOKEN` et `HOSTS_ALLOWED_IDS=thinkpad` en `is_runtime=true, is_buildtime=false` — le buildtime fait fuiter le secret en clair dans `application_deployment_queues.logs` - [ ] Middleware de limite de debit Traefik (~12 req/min) sur le chemin d'ingestion, meme patron que `logto-admin` - [ ] Deploiement declenche manuellement (pas d'auto-deploy : `source_id=null`, uuid `u8000gsg044wsk0oo0w884ok`) - [ ] Fichier `~/.config/maximus-host-agent.env` (chmod 600) et copie figee de l'agent poses sur le ThinkPad, ligne `*/5 * * * *` ajoutee au crontab - [ ] Deux battements consecutifs verifies via `GET /hosts` - [ ] `test-curl.sh` etendu aux deux nouvelles routes - [ ] Procedure d'ajout d'un poste consignee dans `docs/coolify-ops.md` - [ ] Rotation conjointe des deux tokens en cas de perte du portable consignee dans `docs/secret-rotation-ops.md` - [ ] Deploiement Vercel du dashboard (`npx vercel --prod`) une fois la-compagnie-maximus#149 mergee ## Review caveats - ARCHITECTURE (MEDIUM) : si le mount `/data/hosts` est oublie, les fichiers vivent dans la couche du conteneur et disparaissent a chaque deploiement. Symptome trompeur : « les postes se vident tout seuls de temps en temps ». D'ou la verification par `docker inspect`. - SECURITE (CRITIQUE, corrige en spec) : le ThinkPad porte DEJA `HEALTH_TOKEN` en clair dans `defenseurs/.env` pour le cron `defenseur-auto`. Sa perte compromet les deux tokens, qui doivent etre tournes ensemble — la separation des tokens ne protege pas ce poste-la. ## Decisions prises en planification - Issue volontairement exclue du milestone `planned-*` : le triage autopilot-safety ecarte les ops VPS (auth navigateur) et les actions non reversibles. ## Spec source la-compagnie-maximus/spec-plan-monitoring-postes.md + spec-decisions-monitoring-postes.md (Issue 6)
maximus added this to the spec-monitoring-postes milestone 2026-08-15 20:11:13 +00:00
maximus added the
status:ready
type:infra
source:human
labels 2026-08-15 20:11:13 +00:00
maximus added
status:in-progress
and removed
status:ready
labels 2026-08-19 00:19:54 +00:00
Author
Owner

Etat de la mise en service — 2026-08-18

Sept criteres sur onze sont soit tenus, soit prets a partir. Le reste attend deux gestes manuels et un merge amont.

Fait

  • Variables CoolifyHOSTS_INGEST_TOKEN (genere en openssl rand -hex 32) et HOSTS_ALLOWED_IDS=thinkpad, verifiees is_runtime=true is_buildtime=false sur les 4 rows (les jumeaux preview compris : ce sont eux qui reintroduisent la fuite le jour ou les preview deploys sont actives). Le champ passe des le POST sous le nom is_buildtime — c'est l'underscore de is_build_time qui est rejete, pas le moment de l'appel. coolify-ops.md corrige en consequence.
  • test-curl.sh etendu — PR #26, 17 -> 41 cas. Detail dans la PR.
  • Procedure d'ajout d'un postela-compagnie-maximus@7e3ee04, docs/coolify-ops.md.
  • Rotation conjointe des deux tokens — meme commit, docs/secret-rotation-ops.md.
  • Poste prepare — copie figee dans ~/.local/share/maximus-host-agent/, ~/.config/maximus-host-agent.env en 600, --dry-run rend un payload conforme au contrat. Crontab volontairement pas encore pose : le brancher avant que l'API reponde produirait un echec toutes les cinq minutes dans journald pour rien.

Verifie au passage

Baseline pre-deploiement, toutes routes de lecture a 200, et agents-map.json bien present cote VPS — la precondition documentee du deploiement (sinon /defenseurs/findings repond 500) est levee. GET /hosts repond 404 en production : la prod est en retard de plusieurs merges, le deploiement ne sera pas un simple ajout de routes.

Bloque sur deux gestes manuels

  1. Reauth Tailscale SSH — bloque le chown de /data/hosts, le fichier Traefik, le docker inspect et la lecture de journalctl.
  2. Persistent Storage dans l'UI Coolify/data/hosts -> /data/hosts, Directory Mount. Aucun endpoint API (verifie : 404 sur storages, persistent-storages, volumes).

Bloque en amont

  • Deploiement Vercel du dashboardla-compagnie-maximus#149 toujours ouverte. Ce critere ne peut pas tomber dans cette passe.

Ecart assume par rapport a la spec

Le middleware de limite de debit ne peut pas suivre le patron logto-admin. Celui-la vit dans /home/ubuntu/logto/docker-compose.yml, une stack compose geree a la main ; vps-health-api est une app Coolify, dont le compose est regenere a chaque deploiement et dont l'API n'expose aucun champ custom_labels. Retenu apres arbitrage : un fichier dans le repertoire dynamique du proxy, que Coolify ne reecrit pas et que Traefik recharge a chaud.

Deux details qui decident du resultat : PathPrefix('/hosts/') avec la barre finale, sinon le polling du dashboard sur GET /hosts se fait etrangler a 12 req/min lui aussi ; et une priority superieure a celle du routeur genere par Coolify, faute de quoi le middleware n'est jamais applique et le symptome est une absence totale de 429, quel que soit le debit.

Ordre du reste, une fois debloque

Chaque etape est une precondition de la suivante — les variables et les labels sont figes a la creation du conteneur, donc tout ce qui atterrit apres le deploiement ne prend effet qu'au suivant, sans erreur nulle part.

  1. chown 1000:1000 /data/hostsavant le deploiement. Sinon Docker cree le point de montage en root:root, chaque ingestion repond 500, et GET /hosts continue de repondre 200 : la panne ne se voit qu'au moment de compter les battements.
  2. Persistent Storage pose dans l'UI.
  3. Fichier Traefik + rechargement.
  4. Deploiement, une seule fois, a la fin.
  5. docker inspectapres le deploiement, jamais avant : le bind n'existe que sur un conteneur cree apres la pose du storage, inspecter celui d'avant donne un faux negatif. Exiger bind /data/hosts -> /data/hosts rw=true ; un volume nomme choisi par erreur satisfait « il y a un montage » tout en rangeant les snapshots hors de portee.
  6. Re-verifier ls -ldn /data/hosts : un point de montage cree par Docker peut avoir reintroduit root:root.
  7. Smoke des quatre routes de lecture, pas seulement /hosts — la prod saute plusieurs merges d'un coup.
  8. Poussee manuelle, puis crontab en lecture-modification-ecriture : cette machine porte deja cinq taches, un printf | crontab - naif les effacerait.
  9. Compter deux battements sur ~12 min, avec receivedAt qui avance deux fois sur des frontieres de cinq minutes (preuve que ca vient du cron et pas de la main), croise avec journalctl -t host-agent.

Note

Deux constats hors scope, releves en inspectant les variables : PAYPERQ_API_KEY est en is_buildtime=true sur sa row production, et le jumeau preview de HEALTH_TOKEN aussi. C'est exactement la fuite decrite dans coolify-ops.md. Non corriges — hors perimetre de cette issue.

## Etat de la mise en service — 2026-08-18 Sept criteres sur onze sont soit tenus, soit prets a partir. Le reste attend deux gestes manuels et un merge amont. ### Fait - [x] **Variables Coolify** — `HOSTS_INGEST_TOKEN` (genere en `openssl rand -hex 32`) et `HOSTS_ALLOWED_IDS=thinkpad`, verifiees `is_runtime=true is_buildtime=false` sur les **4 rows** (les jumeaux preview compris : ce sont eux qui reintroduisent la fuite le jour ou les preview deploys sont actives). Le champ passe des le POST sous le nom `is_buildtime` — c'est l'underscore de `is_build_time` qui est rejete, pas le moment de l'appel. `coolify-ops.md` corrige en consequence. - [x] **`test-curl.sh` etendu** — PR #26, 17 -> 41 cas. Detail dans la PR. - [x] **Procedure d'ajout d'un poste** — `la-compagnie-maximus@7e3ee04`, `docs/coolify-ops.md`. - [x] **Rotation conjointe des deux tokens** — meme commit, `docs/secret-rotation-ops.md`. - [x] **Poste prepare** — copie figee dans `~/.local/share/maximus-host-agent/`, `~/.config/maximus-host-agent.env` en 600, `--dry-run` rend un payload conforme au contrat. **Crontab volontairement pas encore pose** : le brancher avant que l'API reponde produirait un echec toutes les cinq minutes dans journald pour rien. ### Verifie au passage Baseline pre-deploiement, toutes routes de lecture a 200, et `agents-map.json` bien present cote VPS — la precondition documentee du deploiement (sinon `/defenseurs/findings` repond 500) est levee. `GET /hosts` repond 404 en production : **la prod est en retard de plusieurs merges**, le deploiement ne sera pas un simple ajout de routes. ### Bloque sur deux gestes manuels 1. **Reauth Tailscale SSH** — bloque le `chown` de `/data/hosts`, le fichier Traefik, le `docker inspect` et la lecture de `journalctl`. 2. **Persistent Storage dans l'UI Coolify** — `/data/hosts` -> `/data/hosts`, Directory Mount. Aucun endpoint API (verifie : 404 sur `storages`, `persistent-storages`, `volumes`). ### Bloque en amont - [ ] **Deploiement Vercel du dashboard** — `la-compagnie-maximus#149` toujours ouverte. Ce critere ne peut pas tomber dans cette passe. ### Ecart assume par rapport a la spec Le middleware de limite de debit **ne peut pas suivre le patron `logto-admin`**. Celui-la vit dans `/home/ubuntu/logto/docker-compose.yml`, une stack compose geree a la main ; `vps-health-api` est une app Coolify, dont le compose est regenere a chaque deploiement et dont l'API n'expose aucun champ `custom_labels`. Retenu apres arbitrage : un fichier dans le repertoire dynamique du proxy, que Coolify ne reecrit pas et que Traefik recharge a chaud. Deux details qui decident du resultat : `PathPrefix('/hosts/')` **avec la barre finale**, sinon le polling du dashboard sur `GET /hosts` se fait etrangler a 12 req/min lui aussi ; et une `priority` superieure a celle du routeur genere par Coolify, faute de quoi le middleware n'est jamais applique et le symptome est une absence totale de 429, quel que soit le debit. ### Ordre du reste, une fois debloque Chaque etape est une precondition de la suivante — les variables **et** les labels sont figes a la creation du conteneur, donc tout ce qui atterrit apres le deploiement ne prend effet qu'au suivant, sans erreur nulle part. 1. `chown 1000:1000 /data/hosts` — **avant** le deploiement. Sinon Docker cree le point de montage en `root:root`, chaque ingestion repond 500, et `GET /hosts` continue de repondre 200 : la panne ne se voit qu'au moment de compter les battements. 2. Persistent Storage pose dans l'UI. 3. Fichier Traefik + rechargement. 4. Deploiement, **une seule fois**, a la fin. 5. `docker inspect` — **apres** le deploiement, jamais avant : le bind n'existe que sur un conteneur cree apres la pose du storage, inspecter celui d'avant donne un faux negatif. Exiger `bind /data/hosts -> /data/hosts rw=true` ; un volume nomme choisi par erreur satisfait « il y a un montage » tout en rangeant les snapshots hors de portee. 6. Re-verifier `ls -ldn /data/hosts` : un point de montage cree par Docker peut avoir reintroduit `root:root`. 7. Smoke des quatre routes de lecture, pas seulement `/hosts` — la prod saute plusieurs merges d'un coup. 8. Poussee manuelle, puis crontab en **lecture-modification-ecriture** : cette machine porte deja cinq taches, un `printf | crontab -` naif les effacerait. 9. Compter deux battements sur ~12 min, avec `receivedAt` qui avance deux fois sur des frontieres de cinq minutes (preuve que ca vient du cron et pas de la main), croise avec `journalctl -t host-agent`. ### Note Deux constats hors scope, releves en inspectant les variables : `PAYPERQ_API_KEY` est en `is_buildtime=true` sur sa row **production**, et le jumeau preview de `HEALTH_TOKEN` aussi. C'est exactement la fuite decrite dans `coolify-ops.md`. Non corriges — hors perimetre de cette issue.
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: maximus/vps-health-api#16
No description provided.