# Déploiement production (Synology DS220+ / DSM 7.3) — Astro → Nginx statique

> ✅ **CANONIQUE** — Procédure de référence “prod DS220+ / DSM 7.3”.

> Toute modif de déploiement doit être faite **ici**, via PR sur Gitea/main (pas d’édition à la main en prod).

> Périmètre : build Docker (Node→Nginx), blue/green 8081/8082, Reverse Proxy DSM, smoke, rollback.

> Dépendances critiques : variables PUBLIC_GITEA_* (sinon “Proposer” part en 404/login loop).

> Voir aussi : OPS-REFERENCE.md (index), OPS_COCKPIT.md (checklist), TROUBLESHOOTING.md (incidents).

Dernière mise à jour : 2026-02-01

Ce document décrit une mise en place stable sur NAS :
- build Astro dans une image (Node)
- runtime Nginx statique
- bascule blue/green via Reverse Proxy DSM
- tests fonctionnels (dont “Proposer” → Gitea)

---

## 1) Arborescence recommandée

Dossier racine “courant” :
- `/volume2/docker/archicratie-web/current` (symlink vers la release active)

Contenu attendu :
- `Dockerfile`
- `docker-compose.yml`
- `nginx.conf`
- `.env`
- le code du site (package.json, src/, scripts/, etc.)
- `ops/` (scripts de smoke, etc.)

Releases :
- `/volume2/docker/archicratie-web/releases/<YYYYmmdd-HHMMSS>/app`

---

## 2) Pré-requis DSM

- DSM 7.3 avec accès SSH (admin)
- Docker / Container Manager installé
- Reverse Proxy DSM configuré (Portail des applications)
- Sortie Internet OK depuis le NAS (résolution DNS + accès registry)

---

## 3) Sécurité réseau (important)

On publie le site via **HTTPS 443** sur DSM Reverse Proxy.

Les ports 8081/8082 :
- bindés en **localhost uniquement** (`127.0.0.1:8081:80`, `127.0.0.1:8082:80`)
- **n’ont PAS besoin d’être ouverts** dans le pare-feu WAN
- servent uniquement à DSM Reverse Proxy (loopback)

---

## 4) Variables Gitea (FEATURE “Proposer”)

Le site injecte des variables “publiques” au build :

- `PUBLIC_GITEA_BASE` (URL gitea)
- `PUBLIC_GITEA_OWNER` (**casse sensible**)
- `PUBLIC_GITEA_REPO`

Exemple dans `.env` :
PUBLIC_GITEA_BASE=https://gitea.archicratie.trans-hands.synology.me
PUBLIC_GITEA_OWNER=Archicratia
PUBLIC_GITEA_REPO=archicratie-edition

### 4.1 Piège validé : mauvais owner/repo ⇒ 404/redirect
Symptômes typiques :
- nouvel onglet “Proposer” ouvre `/archicratia/archicratie-web/...` (mauvais)
- Gitea renvoie 404 “page inexistante ou non autorisé”
- ou 303 `/user/login` (si non loggé)

Contrôle rapide :
en sh
for f in .env .env.local .env.production .env.production.local; do
  [ -f "$f" ] && echo "---- $f" && grep -nE '^PUBLIC_GITEA_(BASE|OWNER|REPO)=' "$f" || true
done

En cas d’échec :
- 404 / login loop / mauvais repo → `docs/TROUBLESHOOTING.md#proposer-404`
- double onglet → `docs/TROUBLESHOOTING.md#proposer-double-onglet`

## Diagnostic — “Proposer” (résumé)

**Symptôme :** clic “Proposer” → 404 / login / mauvais repo  
**Cause la plus fréquente :** `PUBLIC_GITEA_OWNER` (casse sensible) ou `PUBLIC_GITEA_REPO` faux.

➡️ Procédure complète (pas-à-pas + commandes) : voir `docs/TROUBLESHOOTING.md#proposer-404`.

## 5) Reverse Proxy DSM (le point clé)

### DSM 7.3 :
Panneau de configuration → Portail des applications → Proxy inversé

Règle pour le site :

Source : HTTPS / archicratie.trans-hands.synology.me / port 443

Destination : HTTP / 127.0.0.1 / port 8081 (BLUE) ou 8082 (GREEN)

Certificat :

Sécurité → Certificat : associer le bon certificat au nom de domaine.

## 6) Notes DS220+ “spécificités”
### 6.1 Build réseau (DNS/apt/npm) : mode robuste

Sur DSM, il arrive que apt-get/npm aient des soucis réseau pendant docker build.
Mesures robustes validées :

build en --network host

apt-get avec retries + ForceIPv4

Exemple (dans Dockerfile) :

apt-get -o Acquire::Retries=5 -o Acquire::ForceIPv4=true ...

### 6.2 BuildKit / buildx / API Docker (DSM)

Certains environnements DSM peuvent :

exiger BuildKit pour --network=host au build

avoir des incompatibilités d’API (client/daemon)

Standard “chez nous” :

activer BuildKit au build

utiliser DOCKER_API_VERSION="$API" si requis sur la machine

Remarque : la valeur de $API est celle validée localement sur le NAS.

### 6.3 Artefacts Mac (PaxHeader / ._ / DS_Store)

Si tu transfères une archive depuis macOS, tu peux embarquer des fichiers parasites.
Conséquence possible : Astro “voit” un faux contenu → erreurs de schema.

Remède :

.dockerignore robuste (voir docs anchors / ops)

éviter les copies “tar” non nettoyées

## 7) Cycle blue/green (procédure protocolaire)
### 7.1 Identifier quel slot est actuellement “en prod”

Comparer l’ETag/Last-Modified public avec 8081/8082 :
curl -kI https://archicratie.trans-hands.synology.me/ | egrep -i 'etag:|last-modified:|server:'
curl -fsSI http://127.0.0.1:8081/ | egrep -i 'etag:|last-modified:'
curl -fsSI http://127.0.0.1:8082/ | egrep -i 'etag:|last-modified:'

Le port qui “match” est le slot actif.

### 7.2 Déployer sur le slot inactif (ex: GREEN 8082)

# Se placer sur le checkout courant :
cd /volume2/docker/archicratie-web/current || exit 1

# Charger .env dans le shell (pour les build-args) :
set -a
. ./.env
set +a

# Rebuild image (exemple green) :
sudo env DOCKER_BUILDKIT=1 DOCKER_API_VERSION="$API" 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 .

# Recreate conteneur (important) :
sudo docker compose up -d --force-recreate --no-build web_green

# Smoke local :
/volume2/docker/archicratie-web/ops/smoke.sh 8082

# Sanity check (fichiers clés) :
curl -fsSI http://127.0.0.1:8082/ | head -n 20
curl -fsSI http://127.0.0.1:8082/favicon.ico | head -n 20
curl -fsSI http://127.0.0.1:8082/favicon.svg | head -n 20

# Contrôle “Proposer” (validation fonctionnelle)

Ouvrir une page chapitre sur le domaine public (ou sur le slot direct si tu testes en local)

Clic Proposer → choix 1 → choix 2

Attendus :

un seul onglet

URL sur .../Archicratia/archicratie-edition/issues/new?...

formulaire visible (si loggé sur Gitea)

issue créée et CI/runner OK (si configuré)

### 7.3 Bascule DSM

Dans DSM Reverse Proxy :

destination 8081 ↔ 8082 (BLUE ↔ GREEN)

### 7.4 Rollback (immédiat)

repointer DSM sur l’ancien port (1 clic)

analyser ensuite le slot inactif

## 8) Favicon (et faux positifs navigateur)
### 8.1 Symptom: Firefox affiche un 504 sur /favicon.ico

Cause fréquemment observée : cache navigateur (Firefox).
Diagnose :

curl -kI https://.../favicon.ico renvoie 200

mais la console navigateur montre encore une erreur
Fix :

désactiver le cache dans l’onglet Réseau, puis reload

ou vider le cache site

### 8.2 Permissions fichiers (si 403)

Si /favicon.svg renvoie 403 :

vérifier droits dans l’image nginx

standard : fichiers 644, répertoires 755 (validé via RUN find ... chmod)

## 9) Exploitation : log driver “db” et erreur “database is locked”

# Erreur observée :

failed to initialize logging driver : database is locked

# Contexte validé :

docker info → Logging Driver: db

# Remède validé :

redémarrer Container Manager (centre de paquets DSM)

# vérifier l’espace disque (df -h) et /tmp

Commandes :
sudo docker info 2>/dev/null | egrep -i 'Logging Driver|Docker Root Dir|Server Version' || true
df -h
df -i

## 10) Références

Pour l’opérationnel minute par minute + tableau de bord : OPS_COCKPIT.md

Pour la synchro Mac/Gitea/NAS : OPS-SYNC-TRIPLE-SOURCE.md

Pour le workflow branches/PR/tags : WORKFLOW-GIT.md

Pour l’ENV : CONFIG-ENV.md

Pour les pannes connues : TROUBLESHOOTING.md

## Depuis quelle machine tu fais ça ?

- **Édition des docs** : **Mac Studio** (éditeur confortable, git propre)
- **Commit/push** : **Mac Studio** (idéal), NAS seulement en “urgence”
- **Déploiement** : **NAS** (évidemment)
- **Gitea docker** : juste l’UI/Actions, pas nécessaire pour écrire les fichiers.

---

## Et maintenant (ordre propre)

1) Sur Mac : crée/complète ce doc (ci-dessus) + les autres docs.
2) Commit “docs: ops runbooks (2026-02-01)” sur `main`.
3) Push → CI verte.
4) Sur NAS : `reset --hard origin/main` (via alpine/git si besoin).
5) Rebuild/deploy **uniquement si** tu as touché Dockerfile/nginx/src/public (pas si docs only).
