69 lines
5.9 KiB
Markdown
69 lines
5.9 KiB
Markdown
# Migration cin-search-tt : hors-Docker vers Docker + SMTP OVH -> Infomaniak
|
|
|
|
## Contexte
|
|
Le 10/07/2026, Nabil signale que la migration SMTP globale vers Infomaniak (faite la veille)
|
|
n'a pas couvert cin-search-tt car cette app tournait en dehors de la stack Docker, dans
|
|
/volume1/web/cin-search-tt (Node.js standalone, jamais containerise).
|
|
|
|
Audit etendu a tout /volume1/web/ : 4 apps Node y etaient hebergees hors-Docker.
|
|
|
|
## Etat trouve
|
|
| App | Etat | Action |
|
|
|---|---|---|
|
|
| cin-search-tt | SMTP sur ssl0.ovh.net, Baserow sur ancien alias nd.i234.me, jamais dockerise | Migre vers Docker |
|
|
| rla | Copie **obsolete** — la vraie version tourne deja proprement dans /volume1/docker/rla-api (Gotenberg/pptx-tt-api deja purges le 04/07) | Archivee (doublon perime) |
|
|
| club-ia | Projet termine (jamais deploye en prod) | Archivee |
|
|
| weblinks | Page HTML statique simple, aucune dependance | Conservee en l'etat dans /volume1/web |
|
|
|
|
## Actions effectuees — cin-search-tt
|
|
1. Copie du code (hors node_modules/zip) vers /volume1/docker/cin-search-tt
|
|
2. `.env` corrige :
|
|
- SMTP_HOST ssl0.ovh.net -> mail.infomaniak.com (port 587, STARTTLS, meme compte nabil.derouiche@ik.me que Baserow/Vaultwarden)
|
|
- BASEROW_API_URL https://baserow.nd.i234.me -> https://baserow.bolbol.tn (alias reseau Docker, regle absolue)
|
|
3. Dockerfile ecrit (node:20-alpine, npm install --omit=dev)
|
|
4. Image buildee via API Docker de Portainer (`POST /api/endpoints/2/docker/build` avec tar de contexte) car `docker` CLI absent du container mcp-nas (hardening 08/07)
|
|
5. Stack deploye via API Portainer (`POST /api/stacks/create/standalone/string`) — **pas de `env_file:`** dans le compose (Portainer ne voit pas les chemins hote arbitraires), variables passees en `environment:` inline a la place
|
|
6. Container `cin-search-tt` : port 3094->3000, reseau `n8n`, volume `/volume1/docker/cin-search-tt/data:/app/data` (persistance database.json)
|
|
7. `ports-registry.md` mis a jour (edite via un container alpine ephemere + bind mount, car le fichier appartient a uid 1026 et mcp-nas n'a plus CAP_DAC_OVERRIDE)
|
|
8. Reverse-proxy DSM `cin.bolbol.tn` -> `localhost:3094` **NON fait** (hors scope API/Docker, a faire manuellement dans DSM Control Panel)
|
|
9. Anciens dossiers archives dans `/volume1/web/.archive/` : `cin-search-tt.archived-20260710-migrated-to-docker`, `rla.archived-20260710-obsolete-superseded-by-docker-rla-api`, `club-ia.archived-20260710`
|
|
|
|
## Pieges decouverts (a capitaliser)
|
|
- **mcp-nas ne peut pas lancer `docker`/`docker compose` directement** (binaire absent, SSH host indisponible depuis le hardening). Solution : API REST Portainer (`/api/endpoints/{id}/docker/build` pour build, `/api/stacks/create/standalone/string` pour deploy).
|
|
- **Portainer ne resout pas `env_file:` avec un chemin hote** dans un stack deploye par API string — le moteur compose de Portainer tourne dans son propre filesystem (`/data/compose/<id>/`), pas celui de l'hote. Toujours utiliser `environment:` inline pour les stacks deployes ainsi.
|
|
- **Volume bind mounts en chemin absolu hote fonctionnent normalement** (resolus par le daemon Docker, pas par Portainer) — contrairement a `env_file:`.
|
|
- **Ecriture de fichiers appartenant a uid 1026 depuis mcp-nas (root) : impossible**, meme en root, a cause de `cap_drop: [ALL]` (pas de CAP_DAC_OVERRIDE). Contournement : creer un container ephemere (alpine) avec bind mount du dossier concerne via l'API Portainer, executer la commande d'ecriture dedans en root reel (container non-hardened), puis le supprimer.
|
|
- **Token Gitea `GITEA_DEPLOY_TOKEN` n'a pas le scope `write:organization` ni `read:user`** — peut lire/ecrire du contenu de repos existants, mais pas creer de nouveaux repos ni lister les users/orgs. Creation de nouveaux repos = a faire manuellement dans l'UI Gitea.
|
|
- **`/volume1/docker/ports-registry.md` n'est pas versionne dans Gitea** (pas de `.git` a la racine de `/volume1/docker`) — mise a jour uniquement in-place sur le NAS.
|
|
|
|
## Reste a faire (hors scope automatisable)
|
|
- Creer la regle reverse-proxy DSM `cin.bolbol.tn` -> `localhost:3094`
|
|
- Creer le repo Gitea `bolbol/cin-search-tt` manuellement (token actuel insuffisant) et y pousser le code
|
|
|
|
## Correctif post-deploiement (10/07/2026, meme session)
|
|
|
|
Nabil a signale "Echec de l'envoi email" apres mise en prod. Deux bugs distincts trouves via les logs container :
|
|
|
|
1. **SMTP code en dur dans server.js** — le transporter nodemailer n'utilisait PAS `config.smtp`
|
|
(qui lit le `.env`) mais des valeurs litterales : `host: 'ssl0.ovh.net'`, `user: 'contact@bolbol.tn'`,
|
|
`pass: '2L2u519wbolbol'`. Corriger le `.env` seul ne changeait donc rien. Patch : les 3 champs
|
|
(host/port/secure/auth) passes en `process.env.SMTP_*`. Le `From` des 2 `sendMail()` (etait
|
|
`contact@bolbol.tn`, adresse OVH desormais coupee) change pour `nabil.derouiche@ik.me` —
|
|
**Infomaniak rejette un From qui ne correspond pas au compte authentifie** (meme contrainte
|
|
deja documentee pour Baserow/Vaultwarden).
|
|
2. **BASEROW_API_URL en https:// echouait en interne** (`ECONNREFUSED 172.27.x.x:443`) —
|
|
sur le reseau Docker `n8n`, l'alias `baserow.bolbol.tn` resout directement vers le container
|
|
Baserow qui n'ecoute qu'en HTTP (port 80, cf. `ports-registry.md` : `3888->80`). Pas de TLS
|
|
en interne. Corrige en `http://baserow.bolbol.tn`.
|
|
|
|
**Piege a capitaliser** : toujours verifier qu'un service qui lit un `.env` via `config.js`
|
|
utilise vraiment ce module partout — un `require('dotenv').config()` en tete de fichier
|
|
n'empeche pas des valeurs codees en dur ailleurs dans le meme fichier. Grep systematique
|
|
sur host/user/pass/api url avant toute migration de credentials.
|
|
|
|
**Piege reseau** : `https://<alias>.bolbol.tn` ne fonctionne QUE depuis l'exterieur (WAN) ou
|
|
un service hors du reseau Docker `n8n` (TLS termine par le reverse-proxy DSM). Un container
|
|
sur le meme reseau `n8n` qu'un alias doit taper en `http://` sur le port interne reel du
|
|
service cible (verifier `ports-registry.md`), jamais supposer que le HTTPS est disponible
|
|
en interne.
|