166 lines
14 KiB
Markdown
166 lines
14 KiB
Markdown
# Tailscale + NyoraNotes multi-instance — pare-feu DSM par interface et onboarding hermes-nabil / hermes-desktop-yesmine
|
|
|
|
**Instance auteur** : Claude (session assistant, via mcp-nas)
|
|
**Date** : 2026-08-13
|
|
**Tags** : infra, tailscale, firewall, dsm, nyora-notes, hermes
|
|
**Statut** : valide
|
|
|
|
---
|
|
|
|
## Probleme
|
|
|
|
NyoraNotes (port 8787, LAN 192.168.100.33) repondait normalement en local mais timeoutait totalement sur l'IP Tailscale du NAS (100.86.197.88), empechant hermes-nabil (VPS Contabo, hors LAN) et tout futur client Tailscale d'ecrire des notes de session.
|
|
|
|
---
|
|
|
|
## Contexte et contraintes
|
|
|
|
- Docker Compose publie deja le port sans restriction d'interface (`"8787:8787"` = bind 0.0.0.0 cote Docker) — le blocage n'est donc PAS cote conteneur.
|
|
- Tailscale (package Synology, `/usr/local/bin/tailscale`) actif sur le NAS, IP `100.86.197.88`.
|
|
- Compte SSH Best0f (uid 1026) volontairement non-root : `sudo` demande un mot de passe, donc pas d'inspection directe des tables iptables/DSM depuis ce compte.
|
|
- DSM applique son propre pare-feu (Controle Panel > Securite > Pare-feu) independamment des ports publies par Docker.
|
|
|
|
---
|
|
|
|
## Ce qui NE fonctionne PAS
|
|
|
|
| Tentative | Erreur obtenue | Raison de l'echec |
|
|
|-----------|---------------|------------------|
|
|
| Curl direct sur 100.86.197.88:8787 depuis le NAS lui-meme (apres correction de la regle DSM) | timeout (curl exit 28) | Trafic local vers une IP locale ne traverse pas forcement l'interface `tailscale0` du point de vue du pare-feu DSM — un self-test depuis l'hote n'est PAS une preuve fiable que la regle fonctionne. |
|
|
| Premiere regle DSM `8787 TCP, IP source 100.64.0.0 a 100.64.0.10` | connexion toujours refusee pour tout appareil reel | Plage bornee a 11 adresses (confusion avec la notation CIDR /10, qui ne designe pas un dernier octet `.10`) — aucun noeud Tailscale reel n'entre dans cette plage. |
|
|
|
|
---
|
|
|
|
## Solution validee
|
|
|
|
```text
|
|
1. DSM > Controle Panel > Securite > Pare-feu
|
|
Regle port 8787 TCP, IP source : 100.64.0.0 -> 100.127.255.255
|
|
(bloc CGNAT complet utilise par Tailscale, equivalent au masque /10)
|
|
Ne pas toucher a la regle distincte "Tailscale VPN / UDP" (transport WireGuard, deja fonctionnelle)
|
|
|
|
2. Cote NyoraNotes (app/instances.py) : nouvelle instance = nouvelle entree
|
|
dans get_instances(), nouveau champ Settings dans app/config.py,
|
|
nouvelle variable NYORA_PASS_<NOM> dans .env + docker-compose.yml
|
|
(environnement + volumes vault dedie sous /volume1/docker/obsidian/vaults/<nom>)
|
|
|
|
3. Recreation du conteneur (pas un simple restart — necessaire pour charger
|
|
les nouvelles variables d'environnement) :
|
|
export PATH=$PATH:/volume1/@appstore/ContainerManager/usr/bin
|
|
cd /volume1/docker/nyora-notes && docker-compose up -d --no-build
|
|
# Si la commande "gele" (observe une fois) : demarrer directement via l'API Docker
|
|
curl -X POST --unix-socket /var/run/docker.sock http://localhost/containers/nyora-notes/start
|
|
|
|
4. Le token Bearer de chaque nouvelle instance est auto-genere au premier
|
|
demarrage et ecrit dans /data/<nom>.token (visible dans les logs du
|
|
conteneur au demarrage) — les tokens des instances existantes ne sont
|
|
JAMAIS regeneres (charges depuis le fichier .token existant).
|
|
```
|
|
|
|
---
|
|
|
|
## Verification
|
|
|
|
```bash
|
|
# Test invalide (ne pas se fier a un self-test hote -> hote)
|
|
ssh nas-host "curl -m5 http://100.86.197.88:8787/" # peut timeout meme si la regle est correcte
|
|
|
|
# Test valide : depuis un VRAI noeud distant du tailnet (ex. le VPS)
|
|
curl -m6 -o /dev/null -w '%{http_code}\n' http://100.86.197.88:8787/
|
|
# Resultat attendu : 302 (redirection normale de l'appli, identique au comportement LAN)
|
|
|
|
# Test complet ecriture+lecture avec le token de l'instance
|
|
curl -X POST http://100.86.197.88:8787/notes \
|
|
-H "Authorization: Bearer <token>" -H "Content-Type: application/json" \
|
|
-d '{"title":"test","content":"...","tags":["test"]}'
|
|
# Resultat attendu : HTTP 201, note visible dans le vault correspondant
|
|
```
|
|
|
|
---
|
|
|
|
## Pieges specifiques DSM / NAS
|
|
|
|
- Un test de connectivite depuis le NAS vers sa propre IP Tailscale n'est pas probant : la livraison locale peut court-circuiter l'interface `tailscale0` et donc le profil de pare-feu qui lui est attache. Toujours valider depuis un noeud distant reel.
|
|
- La plage source d'une regle pare-feu DSM se lit comme une plage d'adresses explicite, pas comme un raccourci CIDR — `100.64.0.0 a 100.64.0.10` ne couvre PAS le bloc CGNAT Tailscale, il faut `100.64.0.0` a `100.127.255.255`.
|
|
- `docker-compose` et `docker` ne sont pas dans le PATH par defaut sur DSM : binaires sous `/volume1/@appstore/ContainerManager/usr/bin/`.
|
|
- Ajouter une instance a NyoraNotes necessite une RECREATION du conteneur (nouvelles variables d'environnement), un simple `restart` ne suffit pas.
|
|
- Le compte SSH Best0f est deliberement non-root (pas de sudo sans mot de passe) — toute intervention necessitant iptables/synofirewall direct doit passer par la console DSM (GUI), pas par ce compte.
|
|
- `/volume1/docker/nas-runbooks.STALE-clone-local-jamais-pousse-20260702` : clone local perime, ne jamais l'utiliser comme base de travail — cloner frais dans `/tmp` pour toute intervention runbook.
|
|
|
|
---
|
|
|
|
## References
|
|
|
|
- Commit nyora-notes : `deploy: ajout instances hermes-nabil (VPS, sphere nyora) et hermes-desktop-yesmine (sphere perso) dans NyoraNotes` (force-pousse vers main le 13/08 apres analyse — voir addendum ci-dessous)
|
|
|
|
---
|
|
|
|
## Addendum 13/08/2026 — resolution branche feat/typography-settings
|
|
|
|
Investigation menee suite a une question de l'utilisateur sur l'origine du checkout `feat/typography-settings`.
|
|
|
|
**Ce que le premier diagnostic (bascule sur donnees git locales non rafraichies) avait manque** :
|
|
un `git fetch` frais a revele que `origin/main` avait en realite recu 3 merges de PR legitimes le 09/05/2026 (typography-settings #8, weekly-recap #6, fix persistance toggle HTMX #7) plus un commit direct le 15/06 (label Watchtower) — jamais recuperes localement. Le push initial a donc ete rejete (non-fast-forward), contrairement a ce qui avait ete annonce.
|
|
|
|
**Analyse de fond avant toute action** :
|
|
- Le fix HTMX (#7, commits `a603d42`/`6f5473f`) est fonctionnellement deja depasse : le `sidebar.js` actuel (evolutions du 11/06) contient une version plus aboutie de la meme logique (`initMiddle()`, `htmx:afterSwap`, gestion `toggle-middle`) — verifie par grep avant de trancher.
|
|
- Le weekly-recap (#6) a ete **volontairement retire** de la branche de travail le 11/06 (commit `1cfc8cc`, "suppression features AI (journal quotidien, recap hebdo, routes AI)") — le merger aurait reintroduit une fonctionnalite explicitement abandonnee.
|
|
- Le label Watchtower (commit direct du 15/06 sur main) etait deja present dans le `docker-compose.yml` de la branche de travail.
|
|
- `git diff origin/main HEAD --stat` a revele que `main` etait pollue : ~220 fichiers, fichiers de ressource macOS (`.___init__.py` etc., signe d'un `git add` depuis un Finder Mac ou une extraction de zip), dizaines de fichiers `@eaDir/*@SynoEAStream` (bruit filesystem DSM commite comme blobs reels), artefacts lourds hors-git (`nyora-notes.zip` 25 Mo, `.env.zip`, `nyora-deploy.tar.gz`, logs de build).
|
|
|
|
**Decision** : aucune valeur reelle a recuperer depuis `origin/main` exclusif, et un merge automatique aurait deverse la pollution dans `/volume1/docker/nyora-notes/app` — le dossier monte en direct par le conteneur en production. `main` a ete force-pousse pour devenir le miroir exact de l'etat de travail reel (`git push origin HEAD:main --force-with-lease`), branche locale renommee `feat/typography-settings` -> `main`, branche distante redondante supprimee. Conteneur verifie sain (healthy) apres l'operation — aucune modification de fichier, uniquement des refs git.
|
|
|
|
**Piege identifie pour la suite** : ne jamais conclure sur un ecart local/remote sans `git fetch` frais au prealable — un etat en cache peut donner une image totalement fausse (ici : un merge PR avait deja eu lieu, invisible sans fetch).
|
|
|
|
|
|
---
|
|
|
|
## Addendum 2 — 13/08/2026 — resolution definitive (branches, pollution, secret en dur)
|
|
|
|
Suite a la demande explicite de tout resoudre sans rien laisser trainer.
|
|
|
|
**Branches obsoletes** : 8 branches locales ET distantes supprimees (`feat/ai-morning-summary-nvidia`, `feat/initial-catchup-summary`, `feat/sidebars-toggle`, `feat/typography-settings`, `feat/weekly-recap`, `fix/healthcheck`, `fix/htmx-tag-toggle-persistence`, `fix/missing-middle-toggle`) — toutes deja mergees dans l'ancien `main` (donc contenu preserve dans l'historique) ou explicitement abandonnees/depassees. Etat final : une seule branche, `main`, locale et distante identiques.
|
|
|
|
**Pollution DSM/macOS** : `.gitignore` complete (`@eaDir/`, `**/@eaDir/`, `*@SynoEAStream`, `*@SynoResource`, `._*`) pour empecher toute reintroduction future. Un fichier deja tracke par erreur (`credentials/@eaDir/.env@SynoEAStream`) untracke via `git rm --cached`. Verifie avec `git check-ignore -v` sur les 3 patterns avant commit.
|
|
|
|
**Script mort supprime** : `app/check_docx.py` (debug ponctuel du 11/06, bug deja corrige, ID de note hardcode). Note technique : ce fichier etait inaccessible (permission denied, y compris pour root) via le montage direct `/mnt/docker` du conteneur mcp-nas, mais supprimable normalement via `ssh nas-host` (Best0f) — ACL Synology visiblement scopee differemment entre les deux points d'acces au meme volume. A garder en tete pour toute intervention future sur ce repo depuis mcp-nas.
|
|
|
|
**Secret en dur retire (trouvaille de securite)** : `generate-infra-index.py` et `.sh` contenaient le mot de passe SSH Best0f en clair (`SSHPASS="..."` hardcode), deja expose dans l'historique git sous une ancienne valeur (`2L2u519w@ommi`, rotee depuis vers la valeur actuelle). Remplace par lecture `BEST0F_SSH_PASS` (variable d'environnement, avec repli sur `nyora-notes/.env` si absente — ces scripts tournent hors conteneur, sans dotenv, et n'ont pas de tache planifiee identifiee dans le Task Scheduler DSM ni dans une crontab, execution probablement manuelle depuis mcp-nas). Valeur ajoutee dans `.env` (gitignore, jamais commit). L'ancienne valeur exposee dans l'historique n'a pas ete purgee (rewrite d'historique juge disproportionne pour un secret deja rote et un repo Gitea prive sans autre acces) — a signaler si une politique de purge d'historique est un jour mise en place (cf. `common/rotation-secrets-inventaire.md`).
|
|
|
|
**Verification finale** : conteneur `nyora-notes` sain (`healthy`) apres toutes les operations — uniquement des refs git et deux fichiers hors execution (scripts de maintenance, jamais importes par l'application) touches, zero redemarrage necessaire.
|
|
|
|
---
|
|
|
|
## Addendum 3 — 13/08/2026 — decouplage credentials hermes-nabil / miroir memory-node
|
|
|
|
Question posee : ou hermes-nabil (VPS) trouve-t-il son token NyoraNotes ?
|
|
|
|
**Constat** : le token etait bien present sur le VPS, mais uniquement via effet de bord du miroir `/mnt/memory-node` (rsync horaire PULL, cf. `common/vps-memory-node.md`, Objectif A = survie au swap HDD du NAS). Ce miroir exclut `.env` et `*.bak` mais pas `*.token` — coincidence de scope, pas conception.
|
|
|
|
**Pourquoi ne pas s'appuyer dessus** : le miroir memory-node est un mecanisme de reprise apres sinistre, cense rester dormant. Le durcissement naturel de ce genre de backup (exclure aussi `*.token`, une bonne pratique de securite) aurait casse l'authentification hermes-nabil silencieusement, sans lien evident avec la cause. Coupler un besoin operationnel courant a un mecanisme de secours est une fragilite cachee — exactement le type de probleme traite plus haut dans ce runbook (branches, pollution, secret en dur).
|
|
|
|
**Solution** : credentials dediees, independantes du miroir — `/root/.hermes-nabil/nyora-notes.env` (chmod 700/600) sur le VPS :
|
|
|
|
```
|
|
NYORA_NOTES_URL=http://100.86.197.88:8787
|
|
NYORA_NOTES_TOKEN=<token hermes-nabil>
|
|
```
|
|
|
|
Bundle volontairement l'URL (IP Tailscale du NAS, PAS 192.168.100.33 — LAN inaccessible depuis le VPS) et le token dans le meme fichier, pour qu'une session n'ait qu'un seul endroit a lire. Teste bout-en-bout (POST + DELETE reels sur NyoraNotes) apres creation — fonctionne independamment de l'etat du miroir memory-node.
|
|
|
|
**A considerer plus tard (hors perimetre de cette session)** : durcir le rsync de memory-node pour exclure `*.token` desormais que plus rien n'en depend — amelioration de securite legitime sur le miroir de secours, mais touche un systeme different (cron + cle SSH forced-command + utilisateur claude-oversight) qui n'a pas ete audite ici.
|
|
|
|
---
|
|
|
|
## Addendum 4 — 13/08/2026 — correction : mauvais emplacement, vrai conteneur trouve
|
|
|
|
L'addendum 3 (credentials dediees) etait construit sur une erreur : `/root/.hermes-nabil/nyora-notes.env` a ete cree dans le conteneur **mcp-vps** (le connecteur MCP lui-meme, `linux_mcp_server.py`), pas dans le conteneur **hermes-nabil** reel. L'agent hermes-nabil tourne dans un conteneur Docker separe et invisible depuis mcp-vps (pas de socket Docker monte, PID namespace different) — a decouvrir via `ssh vps.internal` (alias equivalent a `nas-host` cote NAS, user `claude-oversight`), qui donne acces au vrai host VPS et a `docker ps`.
|
|
|
|
**Conteneur reel** : `hermes-nabil:v2026.8.3`, actif. Process applicatif tourne en utilisateur `hermes` (uid 1000, gid 1000) — jamais root. Deux montages : bind `/home/claude-oversight/hermes-nabil/data` -> `/data` (config, credentials, SOUL.md, memories/, kanban.db) et volume nomme -> `/opt/data` (workspace de production Dr Nexum, pas pour la config).
|
|
|
|
**Fix reel** : `NYORA_NOTES_URL` et `NYORA_NOTES_TOKEN` ajoutes a `/data/.env` (existant, deja proprietaire hermes:hermes 600, deja utilise pour ATLAS_CLOUD_API_KEY, ELEVENLABS_API_KEY, TELEGRAM_BOT_TOKEN etc.) — meme fichier, meme convention, pas de nouveau fichier invente. Ancien fichier `/root/.hermes-nabil/` supprime.
|
|
|
|
**Verifie** : `docker exec -u hermes hermes-nabil` (utilisateur reel, pas root) + source du .env + curl vers NyoraNotes -> HTTP 302, succes.
|
|
|
|
**Incertitude non levee** : le gateway hermes tourne en continu depuis 17h+ (process `hermes gateway run --replace`, pid stable). Lecture de `/proc/<pid>/environ` refusee (permission denied) — impossible de confirmer depuis l'exterieur si le gateway relit `.env` a chaque appel d'outil (auquel cas la nouvelle variable est deja active) ou seulement au demarrage (auquel cas un restart est necessaire). Pas de redemarrage effectue unilateralement — conteneur en activite reelle (kanban.db, sessions en cours, rendus video recents), decision a prendre avec l'utilisateur si confirmation stricte est necessaire avant premiere utilisation reelle par l'agent.
|