16 KiB
OPS — Déploiement Archicratie Web Edition (Mac Studio → DS220+)
Objectif : déployer une nouvelle version du site sur le NAS (DS220+) sans jamais casser la prod, en utilisant un schéma blue/green piloté par DSM Reverse Proxy, avec une procédure robuste même quand docker compose build est instable sur le NAS.
🟧 LEGACY / HISTORIQUE — Ce document n’est plus la source de vérité.
Référence actuelle : docs/DEPLOY_PROD_SYNOLOGY_DS220.md (canonique).
Statut : gelé (on n’édite plus que pour ajouter un lien vers le canonique, si nécessaire).
Raison : doublon → risque de divergence → risque d’erreur en prod.
Si tu lis ceci pour déployer : stop → ouvre le canonique.
⚠️ LEGACY — Ne pas suivre pour déployer. Doc conservé pour historique. Canon :
DEPLOY_PROD_SYNOLOGY_DS220.md+OPS-SYNC-TRIPLE-SOURCE.md.
Pourquoi ce doc existe encore
- Historique : il capture des repères (domaines, ports, logique blue/green) tels qu’ils ont été consolidés pendant la phase d’implémentation.
- Sécurité : éviter la divergence documentaire (un seul pas-à-pas officiel).
- Maintenance : si tu dois déployer, tu suis le canonique ; ici tu ne viens que pour comprendre “d’où ça vient”.
Ce qu’il faut faire aujourd’hui (canonique)
➡️ Déploiement = docs/DEPLOY_PROD_SYNOLOGY_DS220.md (procédure détaillée, à jour).
Schéma (résumé, sans commandes)
- Ne jamais toucher au slot live.
- Construire/tester sur l’autre slot.
- Smoke test.
- Bascule DSM Reverse Proxy (8081 ↔ 8082).
- Rollback DSM si besoin.
🚫 NE PAS UTILISER POUR PROD — ARCHIVE UNIQUEMENT
Archive — ancien pas-à-pas (NE PAS SUIVRE)
⚠️ Archive. Ce contenu est conservé pour mémoire.
0) Repères essentiels
Noms & domaines • Site public (prod) : https://archicratie.trans-hands.synology.me • Gitea public : https://gitea.archicratie.trans-hands.synology.me Attention : tu as eu un “piège” de typo (trans-hands-synology.me ≠ trans-hands.synology.me). Toujours vérifier l’orthographe exacte. Ports locaux NAS • web_blue : 127.0.0.1:8081 → container:80 • web_green : 127.0.0.1:8082 → container:80 • DSM Reverse Proxy pointe soit vers 8081 soit vers 8082. Règle d’or “safe prod” • On ne touche jamais au slot live (celui pointé par DSM). • On construit/teste sur l’autre slot. • On bascule DSM (10 secondes). • On rollback DSM (10 secondes) si besoin.
1) Blue/Green : qui fait quoi ?
Convention simple et pro • blue = slot A (souvent “actif” par défaut) → 8081 • green = slot B (staging/next) → 8082 Mais : la vérité = DSM. Ce n’est pas “blue” ou “green” qui décide : c’est le Reverse Proxy DSM qui pointe vers 8081 ou 8082. ➡️ Donc : • blue et green sont deux environnements identiques • l’un est “live”, l’autre est “next” • après bascule, les rôles s’inversent
2) Arborescence NAS (standard à stabiliser)
Chemin racine : • /volume2/docker/archicratie-web/ Sous-dossiers recommandés : • incoming/ : dépôt d’archives venant du Mac (upload File Station / scp) • releases/ : releases dépliées, horodatées • current : symlink vers la release “courante” (le code utilisé pour builder) • ops/ : scripts d’exploitation (smoke, which-live, helpers) • current__backup_before_cleanup/ : backup historique (optionnel) Exemple sain : /volume2/docker/archicratie-web/ incoming/ archicratie-web-20260130-104937.tar.gz archicratie-web-20260130-104937.tar.gz.sha256 releases/ 20260130-104937/ app/ (code déplié prêt) current -> releases/20260130-104937/app ops/ smoke.sh which-live.sh
3) Permissions NAS (ce qui est “propre”)
Tu as eu des problèmes de release dépliée “root:root” → impossible à lire en user. Politique simple • propriétaire : archicratia:users • dossiers : 750 • fichiers : 640 • incoming peut être 770 si tu y upload souvent via File Station. Commandes (à lancer à la racine) : BASE="/volume2/docker/archicratie-web"
sudo chown -R archicratia:users "$BASE" sudo chmod 750 "$BASE" "$BASE/ops" "$BASE/releases" "$BASE/current__backup_before_cleanup" 2>/dev/null || true sudo chmod 770 "$BASE/incoming" 2>/dev/null || true
Important : options find AVANT les tests
find "$BASE/releases" -maxdepth 3 -type d -exec chmod 750 {} ; find "$BASE/releases" -maxdepth 3 -type f -exec chmod 640 {} ;
⚠️ Éviter chmod 700 * “au hasard” : ça peut te bloquer toi-même + bloquer des outils DSM. Le trio 750/640 est ton bon compromis.
4) Variables Gitea (les 3 variables qui conditionnent “Proposer”)
Dans .env sur le NAS (dans current/ ou dans la release) : PUBLIC_GITEA_BASE=https://gitea.archicratie.trans-hands.synology.me PUBLIC_GITEA_OWNER=Archicratia PUBLIC_GITEA_REPO=archicratie-edition
Point critique : la casse du OWNER Tu as déjà vu le symptôme : • archicratia/archicratie-edition → peut renvoyer 404 • Archicratia/archicratie-edition → OK Donc : OWNER doit être exactement la casse que Gitea attend. Test rapide (NAS) : BASE="https://gitea.archicratie.trans-hands.synology.me" curl -kI "$BASE/Archicratia/archicratie-edition/" | head -n 8 ✅ attendu : HTTP/2 200
5) Côté Mac Studio : préparer une release “propre” (sans scories macOS)
Pourquoi Tu as eu : • fichiers ._* • xattrs LIBARCHIVE.xattr.com.apple.* • warnings à l’extraction ➡️ Ce n’est pas bloquant, mais c’est sale et ça te pollue les releases. Script Mac : release-pack.sh (sans Git, ultra simple) À placer à la racine du repo site/ sur Mac. #!/bin/zsh set -euo pipefail
TS="${1:-$(date +%Y%m%d-%H%M%S)}" NAME="archicratie-web-$TS" OUT_DIR="_release_out" ARCHIVE="$OUT_DIR/$NAME.tar.gz" SHA="$ARCHIVE.sha256"
mkdir -p "$OUT_DIR"
Évite les AppleDouble (._*) + certaines métadonnées
export COPYFILE_DISABLE=1 export COPY_EXTENDED_ATTRIBUTES_DISABLE=1
Nettoyages “safe”
find . -name ".DS_Store" -delete 2>/dev/null || true
Crée un dossier staging
STAGE="$(mktemp -d)" mkdir -p "$STAGE/$NAME"
Copie le repo SANS déchets
rsync -a --delete
--exclude ".git/"
--exclude "node_modules/"
--exclude "dist/"
--exclude ".astro/"
--exclude "release_out/"
--exclude ".DS_Store"
--exclude "__MACOSX/"
--exclude ".*"
./ "$STAGE/$NAME/"
Tar propre
tar -czf "$ARCHIVE" -C "$STAGE" "$NAME"
Checksum
shasum -a 256 "$ARCHIVE" > "$SHA"
echo "OK: $ARCHIVE" echo "OK: $SHA"
Usage : chmod +x release-pack.sh ./release-pack.sh 20260130-104937
Résultat : • _release_out/archicratie-web-20260130-104937.tar.gz • _release_out/archicratie-web-20260130-104937.tar.gz.sha256
6) Transfert vers le NAS
Option A — DSM File Station (simple)
• Upload les 2 fichiers dans :
◦ /volume2/docker/archicratie-web/incoming/
Option B — scp (si SSH)
Depuis le Mac :
scp _release_out/archicratie-web-20260130-104937.tar.gz*
archicratia@192.168.1.20:/volume2/docker/archicratie-web/incoming/
7) NAS : vérifier + déplier une release (procédure canonique)
BASE="/volume2/docker/archicratie-web" TS="20260130-104937"
cd "$BASE"
1) checksum (IMPORTANT)
sha256sum -c "incoming/archicratie-web-$TS.tar.gz.sha256"
2) créer dossier release
rm -rf "releases/$TS" mkdir -p "releases/$TS"
3) extraire
tar -xzf "incoming/archicratie-web-$TS.tar.gz" -C "releases/$TS"
4) pointer APP vers le dossier extrait
APP="$BASE/releases/$TS/archicratie-web-$TS"
option: normaliser en "app"
mv "$APP" "$BASE/releases/$TS/app" APP="$BASE/releases/$TS/app"
5) ownership + perms
sudo chown -R archicratia:users "$BASE/releases/$TS" find "$BASE/releases/$TS" -type d -exec chmod 750 {} ; find "$BASE/releases/$TS" -type f -exec chmod 640 {} ;
6) basculer current (symlink)
ln -sfn "$APP" "$BASE/current"
7) sanity check : compose présent ?
ls -la "$BASE/current/docker-compose.yml" "$BASE/current/Dockerfile" "$BASE/current/nginx.conf" "$BASE/current/.env"
Cas réel déjà rencontré : la release “n’a pas les fichiers ops” Tu as eu un tar “inner” (archicratie-web.tar.gz) qui n’embarque pas docker-compose.yml/Dockerfile/nginx.conf/.env. Règle pro : ces fichiers doivent être dans la release. Fix immédiat si c’est absent (tu l’as déjà fait) : OPS_SRC="$BASE/releases/20260129-174516_clean" cp -a "$OPS_SRC/docker-compose.yml" "$APP/" cp -a "$OPS_SRC/Dockerfile" "$APP/" cp -a "$OPS_SRC/nginx.conf" "$APP/" cp -a "$OPS_SRC/.env" "$APP/.env"
8) Build GREEN sur NAS (robuste) — IMPORTANT
Pourquoi docker compose build n’est PAS fiable sur DS220+ Tu as vu : • Temporary failure resolving 'deb.debian.org' • apt-get update qui part en Ign: puis Err: ➡️ En pratique sur ton NAS : le builder n’a pas toujours le bon réseau, même si build: network: host est déclaré. Procédure “qui marche vraiment” (golden path) ➡️ On build en host network avec docker build, puis on déploie avec compose sans rebuild. cd /volume2/docker/archicratie-web/current
charge les env vars du .env
set -a . ./.env set +a
BUILD image green (host network)
sudo docker build --no-cache --network host
--build-arg PUBLIC_GITEA_BASE="$PUBLIC_GITEA_BASE"
--build-arg PUBLIC_GITEA_OWNER="$PUBLIC_GITEA_OWNER"
--build-arg PUBLIC_GITEA_REPO="$PUBLIC_GITEA_REPO"
-t archicratie-web:green
-f Dockerfile .
Voir Ign: pendant apt-get n’est pas forcément une erreur. Ce qui compte : est-ce qu’il finit par télécharger / réussir. On s’alarme uniquement si on voit Err: ... Temporary failure resolving + exit code non-zéro.
9) Démarrer GREEN (sans impacter BLUE)
cd /volume2/docker/archicratie-web/current
ne jamais lancer "up" sans préciser le service
sudo docker rm -f archicratie-web-green 2>/dev/null || true sudo docker compose up -d --force-recreate --no-build web_green Smoke test (port 8082) : /volume2/docker/archicratie-web/ops/smoke.sh 8082
10) DSM : basculer le Reverse Proxy (10 secondes)
DSM → Panneau de configuration → Portail de connexion (ou “Portail des applications”) → Proxy inversé Trouve la règle : • Source : https://archicratie.trans-hands.synology.me (443) Destination : • pour BLUE : http://127.0.0.1:8081 • pour GREEN : http://127.0.0.1:8082 Tu changes seulement le port, tu “Appliques”. Test immédiat : curl -kI https://archicratie.trans-hands.synology.me/ | head -n 8
11) Rollback (10 secondes)
Si ça ne va pas : • DSM Reverse Proxy → remettre l’ancien port (8081 ou 8082) • refresh navigateur Option pro : ne stoppe pas l’autre container tout de suite (tu peux comparer / investiguer calmement).
12) Ops scripts (à garder dans /volume2/docker/archicratie-web/ops)
smoke.sh (version “complète”) #!/bin/sh set -eu
PORT="${1:-8081}" BASE="http://127.0.0.1:${PORT}"
echo "Smoke test ${BASE}"
curl -fsSI "${BASE}/" | head -n 5 curl -fsSI "${BASE}/pagefind/pagefind.js" | head -n 5 curl -fsSI "${BASE}/pagefind/pagefind-ui.js" | head -n 5 || true curl -fsSI "${BASE}/pagefind/pagefind-ui.css" | head -n 5 || true curl -fsSI "${BASE}/pagefind/pagefind-entry.json" | head -n 5 || true
echo "OK"
which-live.sh (déduire quel port est live) Idée : on compare les Last-Modified ou ETag entre le domaine public et les ports locaux. #!/bin/sh set -eu
DOMAIN="https://archicratie.trans-hands.synology.me" A="http://127.0.0.1:8081" B="http://127.0.0.1:8082"
etag() { curl -ksI "$1/" | awk -F': ' 'tolower($1)=="etag"{print $2}' | tr -d '\r'; } lm() { curl -ksI "$1/" | awk -F': ' 'tolower($1)=="last-modified"{print $2}' | tr -d '\r'; }
E_D="$(etag "$DOMAIN")" E_A="$(etag "$A")" E_B="$(etag "$B")"
echo "DOMAIN ETag: $E_D" echo "8081 ETag: $E_A" echo "8082 ETag: $E_B"
if [ -n "$E_D" ] && [ "$E_D" = "$E_A" ]; then echo "LIVE=8081 (blue slot probable)" elif [ -n "$E_D" ] && [ "$E_D" = "$E_B" ]; then echo "LIVE=8082 (green slot probable)" else echo "LIVE=INCONNU (ETag mismatch) — check Last-Modified:" echo "DOMAIN: $(lm "$DOMAIN")" echo "8081 : $(lm "$A")" echo "8082 : $(lm "$B")" fi
13) Pannes & diagnostics (les vrais cas rencontrés)
A) 504 via DSM Reverse Proxy
Symptôme : HTTP/2 504 côté domaine. Check : 1. le container répond en local : curl -I http://127.0.0.1:8081/ curl -I http://127.0.0.1:8082/ 2. DSM Reverse Proxy destination = http://127.0.0.1:808X (pas https) 3. ports bindés en loopback (recommandé) : 127.0.0.1:808X:80 4. logs container : sudo docker logs --tail=80 archicratie-web-blue sudo docker logs --tail=80 archicratie-web-green
B) “Proposer” ouvre Gitea mais tombe sur 404
C’est quasiment toujours l’un de ces trois points :
1. OWNER/REPO incorrects (casse)
Test :
BASE="https://gitea.archicratie.trans-hands.synology.me"
curl -kI "$BASE/Archicratia/archicratie-edition/" | head
• Si 404 → c’est ton .env / build args.
• La build a embarqué une ancienne config
Vérifie dans le HTML servi (dans le container) :
sudo docker exec -it archicratie-web-green sh -lc
'grep -Rin "const GITEA_BASE" /usr/share/nginx/html | head -n 20'
1. Tu dois voir https://gitea.archicratie.trans-hands.synology.me + bon OWNER/REPO.
2. Problème d’auth / droits Gitea
Si tu es loggé mais “pas autorisé”, vérifier que tu as accès au repo et que l’URL pointe au bon repo.
C) “Proposer” échoue avant Gitea (pas de pop-up, pas de 2 choix)
Check : • console navigateur (JS) • vérifier que le script “Proposer” est bien injecté dans la page (view source) • tester une page simple (ex: /archicratie/)
D) Pagefind n’indexe plus
Ce que tu as déjà observé :
• Pagefind ignore les pages sans data-pagefind-body
• Tu avais bien ~12 pages indexées (log Pagefind)
Check dans le container :
sudo docker exec -it archicratie-web-green sh -lc
'ls -la /usr/share/nginx/html/pagefind | head'
Note :
• GET /pagefind/ peut renvoyer 403 (listing interdit) : ce n’est pas un bug
• tu testes plutôt :
◦ /pagefind/pagefind.js
◦ /pagefind/pagefind-entry.json
E) docker compose build casse sur apt-get update (DNS)
Symptôme :
• Temporary failure resolving 'deb.debian.org'
Diagnostic rapide :
sudo docker run --rm --network host node:22-bookworm-slim sh -lc
'apt-get -o Acquire::ForceIPv4=true update -qq && echo OK_APT'
✅ si OK_APT : ton NAS sait sortir, c’est le builder compose qui est instable → utiliser la golden path : docker build --network host.
14) Dockerfile : version robuste “NAS host-network”
Dans ton Dockerfile, garde :
RUN --network=host apt-get update
&& apt-get install -y --no-install-recommends ca-certificates git
&& rm -rf /var/lib/apt/lists/*
Option “anti-fragile” (retries + IPv4) :
RUN --network=host apt-get -o Acquire::Retries=5 -o Acquire::ForceIPv4=true update
&& apt-get install -y --no-install-recommends ca-certificates git
&& rm -rf /var/lib/apt/lists/*
15) Important : ne pas se faire piéger par le docker.sock
Sur ton DS220+, /var/run/docker.sock est root:root avec 660 → ton user ne peut pas accéder Docker sans sudo. ➡️ Règle : • commandes Docker = sudo docker ... • compose = sudo docker compose ... (Optionnel : alias) alias d='sudo docker' alias dc='sudo docker compose'
16) Workflow résumé “cockpit” (le plus important)
Depuis le Mac : 1. ./release-pack.sh 20260130-104937 2. upload _release_out/.tar.gz → NAS incoming/ Sur le NAS : 1. vérifier checksum 2. déplier releases/$TS + chown/chmod 3. ln -sfn releases/$TS/app current 4. build green : ◦ sudo docker build --network host ... -t archicratie-web:green . 5. run green : ◦ sudo docker compose up -d --force-recreate --no-build web_green 6. smoke : ◦ /volume2/docker/archicratie-web/ops/smoke.sh 8082 7. switch DSM Reverse Proxy 8081 ↔ 8082 8. si souci → rollback DSM
Post-scriptum : ton problème local Mac (Astro “Cannot find module astro/config”) Ce symptôme arrive typiquement quand : • node_modules est incomplet/corrompu • tu as basculé de dossier (ex: un _release_out/... a été pris pour le vrai repo) • ou le process dev a reload sur un tsconfig “nouveau” mais pas les deps Fix standard (dans le vrai dossier site/) : rm -rf node_modules .astro dist npm ci npm run dev