10 KiB
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, IP100.86.197.88. - Compte SSH Best0f (uid 1026) volontairement non-root :
sudodemande 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
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
# 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
tailscale0et 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.10ne couvre PAS le bloc CGNAT Tailscale, il faut100.64.0.0a100.127.255.255. docker-composeetdockerne 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
restartne 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/tmppour 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 : lesidebar.jsactuel (evolutions du 11/06) contient une version plus aboutie de la meme logique (initMiddle(),htmx:afterSwap, gestiontoggle-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.ymlde la branche de travail. git diff origin/main HEAD --stata revele quemainetait pollue : ~220 fichiers, fichiers de ressource macOS (.___init__.pyetc., signe d'ungit adddepuis 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.zip25 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.