chore: package de deploiement prod (Dockerfile, compose, backup/restore, guide)
- Dockerfile multi-stage (build Astro -> runtime node standalone) - docker-compose.prod.yml : Astro builde, ports bindes 127.0.0.1, secrets requis - .env.prod.example : template de prod avec generation des secrets - scripts/backup.sh + restore.sh : migration base Directus + photos - DEPLOY.md : guide pas a pas - .dockerignore : exclusion du .env (anti-fuite de secrets) - untrack du tool-log BYAN (churn) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
bff653acd6
commit
b0030246e4
9 changed files with 454 additions and 0 deletions
|
|
@ -1,6 +1,10 @@
|
||||||
node_modules
|
node_modules
|
||||||
dist
|
dist
|
||||||
.astro
|
.astro
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
.byan-strict
|
||||||
.git
|
.git
|
||||||
.github
|
.github
|
||||||
.claude
|
.claude
|
||||||
|
|
|
||||||
31
.env.prod.example
Normal file
31
.env.prod.example
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
# ============================================================
|
||||||
|
# Variables de PRODUCTION — a copier en `.env` SUR LE SERVEUR
|
||||||
|
# cp .env.prod.example .env puis remplir chaque valeur
|
||||||
|
# Ne JAMAIS commiter le .env rempli (il est gitignore).
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
# --- Domaine public ---
|
||||||
|
# L'URL finale du site (avec https). Sert au SSR + au CORS Directus.
|
||||||
|
PUBLIC_SITE_URL=https://mostuki.fr
|
||||||
|
# URL publique de Directus (sous-domaine admin, derriere ton reverse-proxy).
|
||||||
|
DIRECTUS_PUBLIC_URL=https://admin.mostuki.fr
|
||||||
|
|
||||||
|
# --- Secrets Directus (GENERER des valeurs aleatoires) ---
|
||||||
|
# Genere chacune avec : openssl rand -hex 32
|
||||||
|
DIRECTUS_KEY=
|
||||||
|
DIRECTUS_SECRET=
|
||||||
|
|
||||||
|
# --- Compte admin Directus ---
|
||||||
|
# NE PAS reutiliser changeme-please. Mot de passe long et unique.
|
||||||
|
DIRECTUS_ADMIN_EMAIL=corentin.jog@gmail.com
|
||||||
|
DIRECTUS_ADMIN_PASSWORD=
|
||||||
|
|
||||||
|
# --- Token statique d'API Directus (lecture des contenus par Astro) ---
|
||||||
|
# A generer APRES le premier demarrage (voir DEPLOY.md, etape 5).
|
||||||
|
DIRECTUS_TOKEN=
|
||||||
|
|
||||||
|
# --- Postgres ---
|
||||||
|
POSTGRES_USER=directus
|
||||||
|
# Mot de passe DB long et unique : openssl rand -hex 24
|
||||||
|
POSTGRES_PASSWORD=
|
||||||
|
POSTGRES_DB=directus
|
||||||
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -5,9 +5,13 @@ dist
|
||||||
.env
|
.env
|
||||||
.env.*
|
.env.*
|
||||||
!.env.example
|
!.env.example
|
||||||
|
!.env.prod.example
|
||||||
# Docker volumes
|
# Docker volumes
|
||||||
postgres_data/
|
postgres_data/
|
||||||
directus_uploads/
|
directus_uploads/
|
||||||
directus_extensions/
|
directus_extensions/
|
||||||
# BYAN strict-mode local state
|
# BYAN strict-mode local state
|
||||||
.byan-strict/
|
.byan-strict/
|
||||||
|
|
||||||
|
# BYAN tool log (churn)
|
||||||
|
_byan-output/tool-log.jsonl
|
||||||
|
|
|
||||||
164
DEPLOY.md
Normal file
164
DEPLOY.md
Normal file
|
|
@ -0,0 +1,164 @@
|
||||||
|
# Deploiement Mostuki Photo — guide pas a pas
|
||||||
|
|
||||||
|
Ce guide part du principe que tu as deja un serveur avec Docker + un
|
||||||
|
reverse-proxy (Traefik/nginx) qui gere le TLS et route ton domaine.
|
||||||
|
|
||||||
|
Le principe a retenir : **git porte le code, pas les donnees.** Tes textes,
|
||||||
|
tes series et tes photos vivent dans la base Directus + le volume uploads. Il
|
||||||
|
faut donc les EXPORTER de ta machine et les RESTAURER sur le serveur.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Vue d'ensemble
|
||||||
|
|
||||||
|
```
|
||||||
|
[Ta machine] [Serveur]
|
||||||
|
1. backup.sh --> db.sql.gz --scp--> 6. restore.sh
|
||||||
|
--> uploads.tar.gz |
|
||||||
|
2. git clone
|
||||||
|
3. .env de prod
|
||||||
|
4. up -d --build
|
||||||
|
5. token Directus
|
||||||
|
7. reverse-proxy
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ETAPE 1 — Exporter ton contenu (sur TA machine)
|
||||||
|
|
||||||
|
La stack locale doit tourner (Postgres + Directus up).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/Documents/03_Dev/site-photo
|
||||||
|
bash scripts/backup.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Ca cree `backups/db-<date>.sql.gz` et `backups/uploads-<date>.tar.gz`.
|
||||||
|
Note bien la valeur de `DIRECTUS_TOKEN` de ton `.env` local : tu en auras
|
||||||
|
besoin a l'etape 3 (le token est stocke dans la base, il doit correspondre).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ETAPE 2 — Recuperer le code (sur le SERVEUR)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://git.acadenice.com/Corentin/site-mariage.git mostuki
|
||||||
|
cd mostuki
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ETAPE 3 — Configurer les secrets de prod (sur le SERVEUR)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env.prod.example .env
|
||||||
|
```
|
||||||
|
|
||||||
|
Edite `.env` et remplis chaque valeur :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Genere les 3 secrets aleatoires :
|
||||||
|
openssl rand -hex 32 # -> DIRECTUS_KEY
|
||||||
|
openssl rand -hex 32 # -> DIRECTUS_SECRET
|
||||||
|
openssl rand -hex 24 # -> POSTGRES_PASSWORD
|
||||||
|
```
|
||||||
|
|
||||||
|
- `PUBLIC_SITE_URL` / `DIRECTUS_PUBLIC_URL` : tes vrais domaines (https).
|
||||||
|
- `DIRECTUS_TOKEN` : **la meme valeur que ton `.env` local** (etape 1).
|
||||||
|
- `DIRECTUS_ADMIN_PASSWORD` : un mot de passe fort (sert si la base demarre
|
||||||
|
vide ; sera ecrase par l'admin restaure a l'etape 6 — voir la note).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ETAPE 4 — Demarrer la stack (sur le SERVEUR)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose -f docker-compose.prod.yml up -d --build
|
||||||
|
```
|
||||||
|
|
||||||
|
Le `--build` compile l'image Astro de prod. Verifie que les 3 conteneurs
|
||||||
|
tournent : `docker compose -f docker-compose.prod.yml ps`.
|
||||||
|
|
||||||
|
A ce stade la base est VIDE (branding "Laurel & Vow" par defaut). On la
|
||||||
|
remplace avec ton contenu a l'etape 6.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ETAPE 5 — Transferer les backups (depuis TA machine)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scp backups/db-*.sql.gz backups/uploads-*.tar.gz user@serveur:~/mostuki/backups/
|
||||||
|
```
|
||||||
|
|
||||||
|
(cree le dossier `backups/` sur le serveur s'il n'existe pas)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ETAPE 6 — Restaurer ton contenu (sur le SERVEUR)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash scripts/restore.sh backups/db-<date>.sql.gz backups/uploads-<date>.tar.gz
|
||||||
|
docker compose -f docker-compose.prod.yml restart directus astro
|
||||||
|
```
|
||||||
|
|
||||||
|
> **IMPORTANT securite.** La base restauree contient ton compte admin LOCAL,
|
||||||
|
> avec son ancien mot de passe (`changeme-please`). Connecte-toi tout de suite
|
||||||
|
> sur Directus admin et change le mot de passe + l'email :
|
||||||
|
> Settings -> Users -> ton compte -> nouveau mot de passe.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ETAPE 7 — Brancher le reverse-proxy (sur le SERVEUR)
|
||||||
|
|
||||||
|
Les services ecoutent en local uniquement :
|
||||||
|
- Site Astro -> `127.0.0.1:4321`
|
||||||
|
- Directus -> `127.0.0.1:8055`
|
||||||
|
|
||||||
|
Configure ton reverse-proxy pour router :
|
||||||
|
- `PUBLIC_SITE_URL` (ex: mostuki.fr) -> `127.0.0.1:4321`
|
||||||
|
- `DIRECTUS_PUBLIC_URL` (ex: admin.mostuki.fr) -> `127.0.0.1:8055`
|
||||||
|
|
||||||
|
Avec TLS (Let's Encrypt) sur les deux.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ETAPE 8 — Verifications finales
|
||||||
|
|
||||||
|
- [ ] La home affiche bien "Mostuki" (pas "Laurel & Vow") -> sinon la restore
|
||||||
|
DB n'a pas pris, relance l'etape 6.
|
||||||
|
- [ ] Les photos des series s'affichent (proxy `/api/files/...` OK).
|
||||||
|
- [ ] Le formulaire `/contact` enregistre bien (verifie dans Directus admin,
|
||||||
|
collection `contact_requests`).
|
||||||
|
- [ ] Mot de passe admin Directus change (etape 6).
|
||||||
|
- [ ] Port 8055 NON accessible publiquement (seulement via ton sous-domaine
|
||||||
|
admin derriere le proxy).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Mises a jour ulterieures (code uniquement)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/mostuki
|
||||||
|
git pull
|
||||||
|
docker compose -f docker-compose.prod.yml up -d --build
|
||||||
|
```
|
||||||
|
|
||||||
|
La base et les photos ne sont pas touchees (volumes persistants).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Sauvegardes regulieres
|
||||||
|
|
||||||
|
Relance `bash scripts/backup.sh` periodiquement (sur le serveur, en adaptant
|
||||||
|
`PG_CONTAINER=mostuki-postgres DIRECTUS_CONTAINER=mostuki-directus`) et copie
|
||||||
|
les archives ailleurs. C'est ton seul filet en cas de perte du serveur.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Note : email du formulaire de contact
|
||||||
|
|
||||||
|
A ce jour, une demande de contact est STOCKEE dans Directus mais n'envoie
|
||||||
|
AUCUN email de notification (TODO dans `src/pages/api/contact.ts`). Pense a
|
||||||
|
checker la collection `contact_requests` regulierement, ou demande l'ajout de
|
||||||
|
la notif email (provider a choisir : Resend recommande) avant la mise en ligne.
|
||||||
|
```
|
||||||
37
Dockerfile
Normal file
37
Dockerfile
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
# Build de production Astro SSR (adapter node standalone).
|
||||||
|
# Multi-stage : on compile dans une image lourde, on ne garde que le runtime.
|
||||||
|
|
||||||
|
# ---- Stage 1 : build ----
|
||||||
|
FROM node:22-alpine AS build
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Dependances (cache : ne se reinstalle que si package*.json change)
|
||||||
|
COPY package.json package-lock.json* ./
|
||||||
|
RUN npm ci
|
||||||
|
|
||||||
|
# Source + build
|
||||||
|
COPY astro.config.mjs ./
|
||||||
|
COPY tsconfig.json* ./
|
||||||
|
COPY src ./src
|
||||||
|
COPY public ./public
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# ---- Stage 2 : runtime ----
|
||||||
|
FROM node:22-alpine AS runtime
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
# Le serveur standalone @astrojs/node lit HOST et PORT
|
||||||
|
ENV HOST=0.0.0.0
|
||||||
|
ENV PORT=4321
|
||||||
|
|
||||||
|
# Toutes les deps du projet sont des "dependencies" (pas de devDependencies),
|
||||||
|
# le runtime SSR en a besoin (@astrojs/node, @directus/sdk).
|
||||||
|
COPY package.json package-lock.json* ./
|
||||||
|
RUN npm ci --omit=dev && npm cache clean --force
|
||||||
|
|
||||||
|
# Artefact compile uniquement
|
||||||
|
COPY --from=build /app/dist ./dist
|
||||||
|
|
||||||
|
EXPOSE 4321
|
||||||
|
CMD ["node", "./dist/server/entry.mjs"]
|
||||||
|
|
@ -821,3 +821,53 @@
|
||||||
{"timestamp":"2026-06-15T08:30:04.097Z","phase":"pre","tool":"Edit","summary":"/Users/corentinjoguet/Documents/03_Dev/site-photo/.gitignore","est_input_tokens":81}
|
{"timestamp":"2026-06-15T08:30:04.097Z","phase":"pre","tool":"Edit","summary":"/Users/corentinjoguet/Documents/03_Dev/site-photo/.gitignore","est_input_tokens":81}
|
||||||
{"timestamp":"2026-06-15T08:30:04.145Z","phase":"post","tool":"Edit","ok":true,"failure_kind":null,"est_output_tokens":175}
|
{"timestamp":"2026-06-15T08:30:04.145Z","phase":"post","tool":"Edit","ok":true,"failure_kind":null,"est_output_tokens":175}
|
||||||
{"timestamp":"2026-06-15T08:30:15.998Z","phase":"pre","tool":"Bash","summary":"Init git, stage, audit for secrets before commit","est_input_tokens":217}
|
{"timestamp":"2026-06-15T08:30:15.998Z","phase":"pre","tool":"Bash","summary":"Init git, stage, audit for secrets before commit","est_input_tokens":217}
|
||||||
|
{"timestamp":"2026-06-15T08:30:16.597Z","phase":"post","tool":"Bash","ok":true,"failure_kind":null,"est_output_tokens":224}
|
||||||
|
{"timestamp":"2026-06-15T08:30:37.390Z","phase":"pre","tool":"Bash","summary":"Commit and add remote","est_input_tokens":107}
|
||||||
|
{"timestamp":"2026-06-15T08:30:37.547Z","phase":"post","tool":"Bash","ok":true,"failure_kind":null,"est_output_tokens":66}
|
||||||
|
{"timestamp":"2026-06-15T08:30:40.622Z","phase":"pre","tool":"Bash","summary":"Push main to origin","est_input_tokens":40}
|
||||||
|
{"timestamp":"2026-06-15T08:30:42.728Z","phase":"post","tool":"Bash","ok":true,"failure_kind":null,"est_output_tokens":70}
|
||||||
|
{"timestamp":"2026-06-15T08:53:57.991Z","phase":"pre","tool":"Bash","summary":"Check seed default content values","est_input_tokens":78}
|
||||||
|
{"timestamp":"2026-06-15T08:54:00.790Z","phase":"post","tool":"Bash","ok":true,"failure_kind":null,"est_output_tokens":212}
|
||||||
|
{"timestamp":"2026-06-15T08:55:31.468Z","phase":"pre","tool":"Bash","summary":"Check runtime env reading pattern","est_input_tokens":140}
|
||||||
|
{"timestamp":"2026-06-15T08:55:31.536Z","phase":"post","tool":"Bash","ok":true,"failure_kind":null,"est_output_tokens":265}
|
||||||
|
{"timestamp":"2026-06-15T08:55:43.735Z","phase":"pre","tool":"Bash","summary":"Check dockerignore","est_input_tokens":84}
|
||||||
|
{"timestamp":"2026-06-15T08:55:43.798Z","phase":"post","tool":"Bash","ok":true,"failure_kind":null,"est_output_tokens":83}
|
||||||
|
{"timestamp":"2026-06-15T08:56:24.959Z","phase":"pre","tool":"Read","summary":"/Users/corentinjoguet/Documents/03_Dev/site-photo/.dockerignore","est_input_tokens":20}
|
||||||
|
{"timestamp":"2026-06-15T08:56:24.995Z","phase":"post","tool":"Read","ok":true,"failure_kind":null,"est_output_tokens":76}
|
||||||
|
{"timestamp":"2026-06-15T08:56:28.421Z","phase":"pre","tool":"Edit","summary":"/Users/corentinjoguet/Documents/03_Dev/site-photo/.dockerignore","est_input_tokens":60}
|
||||||
|
{"timestamp":"2026-06-15T08:56:28.462Z","phase":"post","tool":"Edit","ok":true,"failure_kind":null,"est_output_tokens":155}
|
||||||
|
{"timestamp":"2026-06-15T08:56:39.102Z","phase":"pre","tool":"Write","summary":"/Users/corentinjoguet/Documents/03_Dev/site-photo/Dockerfile","est_input_tokens":279}
|
||||||
|
{"timestamp":"2026-06-15T08:56:39.148Z","phase":"post","tool":"Write","ok":true,"failure_kind":null,"est_output_tokens":298}
|
||||||
|
{"timestamp":"2026-06-15T08:56:58.736Z","phase":"pre","tool":"Write","summary":"/Users/corentinjoguet/Documents/03_Dev/site-photo/docker-compose.prod.yml","est_input_tokens":722}
|
||||||
|
{"timestamp":"2026-06-15T08:56:58.786Z","phase":"post","tool":"Write","ok":true,"failure_kind":null,"est_output_tokens":741}
|
||||||
|
{"timestamp":"2026-06-15T08:57:10.618Z","phase":"pre","tool":"Write","summary":"/Users/corentinjoguet/Documents/03_Dev/site-photo/.env.prod.example","est_input_tokens":321}
|
||||||
|
{"timestamp":"2026-06-15T08:57:10.657Z","phase":"post","tool":"Write","ok":true,"failure_kind":null,"est_output_tokens":341}
|
||||||
|
{"timestamp":"2026-06-15T08:57:24.754Z","phase":"pre","tool":"Write","summary":"/Users/corentinjoguet/Documents/03_Dev/site-photo/scripts/backup.sh","est_input_tokens":430}
|
||||||
|
{"timestamp":"2026-06-15T08:57:24.804Z","phase":"post","tool":"Write","ok":true,"failure_kind":null,"est_output_tokens":449}
|
||||||
|
{"timestamp":"2026-06-15T08:57:38.885Z","phase":"pre","tool":"Write","summary":"/Users/corentinjoguet/Documents/03_Dev/site-photo/scripts/restore.sh","est_input_tokens":510}
|
||||||
|
{"timestamp":"2026-06-15T08:57:38.924Z","phase":"post","tool":"Write","ok":true,"failure_kind":null,"est_output_tokens":529}
|
||||||
|
{"timestamp":"2026-06-15T08:57:46.216Z","phase":"pre","tool":"Bash","summary":"chmod scripts and check docker","est_input_tokens":79}
|
||||||
|
{"timestamp":"2026-06-15T08:57:46.577Z","phase":"post","tool":"Bash","ok":true,"failure_kind":null,"est_output_tokens":30}
|
||||||
|
{"timestamp":"2026-06-15T08:57:51.096Z","phase":"pre","tool":"Bash","summary":"Check docker daemon / colima","est_input_tokens":65}
|
||||||
|
{"timestamp":"2026-06-15T08:57:52.126Z","phase":"post","tool":"Bash","ok":true,"failure_kind":null,"est_output_tokens":49}
|
||||||
|
{"timestamp":"2026-06-15T08:58:11.383Z","phase":"pre","tool":"Bash","summary":"Validate scripts and compose coherence offline","est_input_tokens":232}
|
||||||
|
{"timestamp":"2026-06-15T08:58:11.551Z","phase":"post","tool":"Bash","ok":true,"failure_kind":null,"est_output_tokens":234}
|
||||||
|
{"timestamp":"2026-06-15T08:58:28.296Z","phase":"pre","tool":"Read","summary":"/Users/corentinjoguet/Documents/03_Dev/site-photo/scripts/restore.sh","est_input_tokens":27}
|
||||||
|
{"timestamp":"2026-06-15T08:58:28.337Z","phase":"post","tool":"Read","ok":true,"failure_kind":null,"est_output_tokens":152}
|
||||||
|
{"timestamp":"2026-06-15T08:58:36.252Z","phase":"pre","tool":"Read","summary":"/Users/corentinjoguet/Documents/03_Dev/site-photo/scripts/restore.sh","est_input_tokens":27}
|
||||||
|
{"timestamp":"2026-06-15T08:58:36.294Z","phase":"post","tool":"Read","ok":true,"failure_kind":null,"est_output_tokens":169}
|
||||||
|
{"timestamp":"2026-06-15T08:58:46.411Z","phase":"pre","tool":"Bash","summary":"Count quotes in restore.sh","est_input_tokens":104}
|
||||||
|
{"timestamp":"2026-06-15T08:58:46.471Z","phase":"post","tool":"Bash","ok":true,"failure_kind":null,"est_output_tokens":162}
|
||||||
|
{"timestamp":"2026-06-15T08:59:07.897Z","phase":"pre","tool":"Bash","summary":"Re-run bash -n on restore.sh","est_input_tokens":62}
|
||||||
|
{"timestamp":"2026-06-15T08:59:07.952Z","phase":"post","tool":"Bash","ok":true,"failure_kind":null,"est_output_tokens":73}
|
||||||
|
{"timestamp":"2026-06-15T08:59:19.835Z","phase":"pre","tool":"Edit","summary":"/Users/corentinjoguet/Documents/03_Dev/site-photo/scripts/restore.sh","est_input_tokens":80}
|
||||||
|
{"timestamp":"2026-06-15T08:59:19.876Z","phase":"post","tool":"Edit","ok":true,"failure_kind":null,"est_output_tokens":685}
|
||||||
|
{"timestamp":"2026-06-15T08:59:23.527Z","phase":"pre","tool":"Bash","summary":"Re-validate both scripts","est_input_tokens":59}
|
||||||
|
{"timestamp":"2026-06-15T08:59:23.586Z","phase":"post","tool":"Bash","ok":true,"failure_kind":null,"est_output_tokens":29}
|
||||||
|
{"timestamp":"2026-06-15T09:00:14.377Z","phase":"pre","tool":"Write","summary":"/Users/corentinjoguet/Documents/03_Dev/site-photo/DEPLOY.md","est_input_tokens":1274}
|
||||||
|
{"timestamp":"2026-06-15T09:00:14.431Z","phase":"post","tool":"Write","ok":true,"failure_kind":null,"est_output_tokens":1294}
|
||||||
|
{"timestamp":"2026-06-15T09:00:22.323Z","phase":"pre","tool":"Bash","summary":"Stage and show changes","est_input_tokens":47}
|
||||||
|
{"timestamp":"2026-06-15T09:00:22.425Z","phase":"post","tool":"Bash","ok":true,"failure_kind":null,"est_output_tokens":69}
|
||||||
|
{"timestamp":"2026-06-15T09:00:34.099Z","phase":"pre","tool":"Edit","summary":"/Users/corentinjoguet/Documents/03_Dev/site-photo/.gitignore","est_input_tokens":51}
|
||||||
|
{"timestamp":"2026-06-15T09:00:34.137Z","phase":"post","tool":"Edit","ok":true,"failure_kind":null,"est_output_tokens":157}
|
||||||
|
{"timestamp":"2026-06-15T09:00:43.652Z","phase":"pre","tool":"Bash","summary":"Fix tracking, verify env template included","est_input_tokens":147}
|
||||||
|
|
|
||||||
79
docker-compose.prod.yml
Normal file
79
docker-compose.prod.yml
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
# Stack de PRODUCTION Mostuki Photo.
|
||||||
|
#
|
||||||
|
# Difference avec docker-compose.yml (dev) :
|
||||||
|
# - Astro est BUILDE (Dockerfile multi-stage) au lieu de tourner en mode dev
|
||||||
|
# - les ports sont bindes sur 127.0.0.1 : seul le reverse-proxy de l'hote y accede,
|
||||||
|
# rien n'est expose directement sur internet
|
||||||
|
# - aucun secret n'a de valeur par defaut : les vars DOIVENT etre fournies (.env)
|
||||||
|
#
|
||||||
|
# Lancement : docker compose -f docker-compose.prod.yml up -d --build
|
||||||
|
# Le reverse-proxy de l'hote (Traefik/nginx) route ton domaine vers 127.0.0.1:4321
|
||||||
|
# (site) et un sous-domaine admin vers 127.0.0.1:8055 (Directus) si besoin.
|
||||||
|
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
container_name: mostuki-postgres
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: ${POSTGRES_USER:?POSTGRES_USER requis}
|
||||||
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD requis}
|
||||||
|
POSTGRES_DB: ${POSTGRES_DB:?POSTGRES_DB requis}
|
||||||
|
volumes:
|
||||||
|
- postgres_data:/var/lib/postgresql/data
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "pg_isready", "-U", "${POSTGRES_USER}"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
directus:
|
||||||
|
image: directus/directus:11
|
||||||
|
container_name: mostuki-directus
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
postgres:
|
||||||
|
condition: service_healthy
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:8055:8055"
|
||||||
|
volumes:
|
||||||
|
- directus_uploads:/directus/uploads
|
||||||
|
- directus_extensions:/directus/extensions
|
||||||
|
environment:
|
||||||
|
KEY: ${DIRECTUS_KEY:?DIRECTUS_KEY requis}
|
||||||
|
SECRET: ${DIRECTUS_SECRET:?DIRECTUS_SECRET requis}
|
||||||
|
ADMIN_EMAIL: ${DIRECTUS_ADMIN_EMAIL:?DIRECTUS_ADMIN_EMAIL requis}
|
||||||
|
ADMIN_PASSWORD: ${DIRECTUS_ADMIN_PASSWORD:?DIRECTUS_ADMIN_PASSWORD requis}
|
||||||
|
DB_CLIENT: "pg"
|
||||||
|
DB_HOST: "postgres"
|
||||||
|
DB_PORT: "5432"
|
||||||
|
DB_DATABASE: ${POSTGRES_DB}
|
||||||
|
DB_USER: ${POSTGRES_USER}
|
||||||
|
DB_PASSWORD: ${POSTGRES_PASSWORD}
|
||||||
|
CACHE_ENABLED: "false"
|
||||||
|
WEBSOCKETS_ENABLED: "true"
|
||||||
|
PUBLIC_URL: ${DIRECTUS_PUBLIC_URL:?DIRECTUS_PUBLIC_URL requis}
|
||||||
|
CORS_ENABLED: "true"
|
||||||
|
CORS_ORIGIN: ${PUBLIC_SITE_URL:?PUBLIC_SITE_URL requis}
|
||||||
|
|
||||||
|
astro:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
container_name: mostuki-astro
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
- directus
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:4321:4321"
|
||||||
|
environment:
|
||||||
|
ASTRO_TELEMETRY_DISABLED: "1"
|
||||||
|
# Astro parle a Directus par le reseau interne Docker (pas par le domaine public)
|
||||||
|
DIRECTUS_URL: "http://directus:8055"
|
||||||
|
DIRECTUS_TOKEN: ${DIRECTUS_TOKEN:?DIRECTUS_TOKEN requis}
|
||||||
|
PUBLIC_SITE_URL: ${PUBLIC_SITE_URL}
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres_data:
|
||||||
|
directus_uploads:
|
||||||
|
directus_extensions:
|
||||||
41
scripts/backup.sh
Executable file
41
scripts/backup.sh
Executable file
|
|
@ -0,0 +1,41 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# ============================================================
|
||||||
|
# backup.sh — emporte TON CONTENU (base Directus + photos)
|
||||||
|
#
|
||||||
|
# A lancer la ou la stack tourne deja (ta machine locale).
|
||||||
|
# Produit dans ./backups/ :
|
||||||
|
# - db-<date>.sql.gz : dump complet Postgres (textes, series, contacts)
|
||||||
|
# - uploads-<date>.tar.gz : toutes les photos uploadees dans Directus
|
||||||
|
#
|
||||||
|
# Usage : bash scripts/backup.sh
|
||||||
|
# Conteneurs (override si besoin) :
|
||||||
|
# PG_CONTAINER=... DIRECTUS_CONTAINER=... bash scripts/backup.sh
|
||||||
|
# ============================================================
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
cd "$(dirname "$0")/.."
|
||||||
|
|
||||||
|
# Charge .env pour POSTGRES_USER / POSTGRES_DB
|
||||||
|
if [ -f .env ]; then set -a; . ./.env; set +a; fi
|
||||||
|
|
||||||
|
PG_CONTAINER="${PG_CONTAINER:-laurel-vow-postgres}"
|
||||||
|
DIRECTUS_CONTAINER="${DIRECTUS_CONTAINER:-laurel-vow-directus}"
|
||||||
|
PG_USER="${POSTGRES_USER:-directus}"
|
||||||
|
PG_DB="${POSTGRES_DB:-directus}"
|
||||||
|
|
||||||
|
STAMP="$(date +%Y%m%d-%H%M%S)"
|
||||||
|
OUT="backups"
|
||||||
|
mkdir -p "$OUT"
|
||||||
|
|
||||||
|
echo "==> Dump base Postgres ($PG_CONTAINER / db=$PG_DB)"
|
||||||
|
docker exec "$PG_CONTAINER" pg_dump -U "$PG_USER" "$PG_DB" | gzip > "$OUT/db-$STAMP.sql.gz"
|
||||||
|
|
||||||
|
echo "==> Archive des photos (uploads Directus)"
|
||||||
|
# /directus/uploads est le chemin des fichiers dans le conteneur Directus
|
||||||
|
docker exec "$DIRECTUS_CONTAINER" tar czf - -C /directus/uploads . > "$OUT/uploads-$STAMP.tar.gz"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "OK. Fichiers crees :"
|
||||||
|
ls -lh "$OUT/db-$STAMP.sql.gz" "$OUT/uploads-$STAMP.tar.gz"
|
||||||
|
echo ""
|
||||||
|
echo "Transfere ces 2 fichiers sur le serveur, puis lance scripts/restore.sh la-bas."
|
||||||
44
scripts/restore.sh
Executable file
44
scripts/restore.sh
Executable file
|
|
@ -0,0 +1,44 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# ============================================================
|
||||||
|
# restore.sh — restaure TON CONTENU sur le serveur de prod
|
||||||
|
#
|
||||||
|
# A lancer SUR LE SERVEUR, apres avoir demarre la stack prod
|
||||||
|
# (docker compose -f docker-compose.prod.yml up -d) et transfere
|
||||||
|
# les 2 fichiers de backup dans ./backups/.
|
||||||
|
#
|
||||||
|
# Usage :
|
||||||
|
# bash scripts/restore.sh backups/db-XXXX.sql.gz backups/uploads-XXXX.tar.gz
|
||||||
|
#
|
||||||
|
# Conteneurs prod (override si besoin) :
|
||||||
|
# PG_CONTAINER=... DIRECTUS_CONTAINER=... bash scripts/restore.sh ...
|
||||||
|
# ============================================================
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
cd "$(dirname "$0")/.."
|
||||||
|
|
||||||
|
DB_DUMP="${1:?Chemin du dump DB requis (ex: backups/db-XXXX.sql.gz)}"
|
||||||
|
UPLOADS_TAR="${2:?Chemin de l archive uploads requis (ex: backups/uploads-XXXX.tar.gz)}"
|
||||||
|
|
||||||
|
if [ -f .env ]; then set -a; . ./.env; set +a; fi
|
||||||
|
|
||||||
|
PG_CONTAINER="${PG_CONTAINER:-mostuki-postgres}"
|
||||||
|
DIRECTUS_CONTAINER="${DIRECTUS_CONTAINER:-mostuki-directus}"
|
||||||
|
PG_USER="${POSTGRES_USER:-directus}"
|
||||||
|
PG_DB="${POSTGRES_DB:-directus}"
|
||||||
|
|
||||||
|
echo "ATTENTION : ceci ECRASE la base '$PG_DB' et les photos du serveur."
|
||||||
|
read -r -p "Continuer ? (tape oui) " ans
|
||||||
|
[ "$ans" = "oui" ] || { echo "Annule."; exit 1; }
|
||||||
|
|
||||||
|
echo "==> Restauration base Postgres ($PG_CONTAINER)"
|
||||||
|
# Recree un schema propre avant import pour eviter les doublons
|
||||||
|
docker exec -i "$PG_CONTAINER" psql -U "$PG_USER" -d "$PG_DB" \
|
||||||
|
-c "DROP SCHEMA public CASCADE; CREATE SCHEMA public;"
|
||||||
|
gunzip -c "$DB_DUMP" | docker exec -i "$PG_CONTAINER" psql -U "$PG_USER" -d "$PG_DB"
|
||||||
|
|
||||||
|
echo "==> Restauration des photos (uploads Directus)"
|
||||||
|
docker exec -i "$DIRECTUS_CONTAINER" sh -c 'rm -rf /directus/uploads/* && tar xzf - -C /directus/uploads' < "$UPLOADS_TAR"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "OK. Redemarre Directus pour qu'il reprenne la base restauree :"
|
||||||
|
echo " docker compose -f docker-compose.prod.yml restart directus astro"
|
||||||
Loading…
Add table
Reference in a new issue