chore(docker): docker-compose.yml standalone portable + .env local-first
All checks were successful
All checks were successful
Le repo ship desormais un docker-compose.yml qui tourne EN LOCAL sans rien configurer (`docker compose up -d` -> http://kiosk.localhost:8080 et http://admin.localhost:8080), facon projet open-source self-hostable. - docker-compose.yml : reseau interne seul, wakdo-web publie ${HTTP_PORT:-8080}:80, plus de dependance au reseau externe Traefik ni de labels. Commentaires retires. - Renommage TRAEFIK_DOMAIN_* -> APP_HOST_* (ce sont les ServerName des deux vhosts Apache, pas du Traefik) : vhost.conf + compose. Defaut local *.localhost. - .env.example : local-first (HTTP_PORT, APP_HOST_*=*.localhost, APP_URL_*/CORS sur localhost, valeurs DB dev qui marchent sans edition). Les variables proxy (REVERSE_PROXY_NETWORK) sont reclassees dans un bloc "Deploiement prod" optionnel. - Prod : chaque hote derriere un reverse proxy maintient son propre docker-compose.prod.yml (gitignore, hors repo) ; meme stack exposee via Traefik sans port hote. README : quickstart local 3 lignes + section prod separee (l'install Docker Debian inline est remplacee par un lien). Verifie : `docker compose config` valide pour les deux fichiers (base = port publie sans reverse_proxy ; prod = reverse_proxy + labels Host(APP_HOST_*) sans port). Smoke-test runtime `docker compose up` a faire sur machine propre (les container_name fixes empechent un up parallele a la stack en cours).
This commit is contained in:
parent
e613adc24a
commit
0028e2a79c
5 changed files with 78 additions and 323 deletions
119
.env.example
119
.env.example
|
|
@ -3,17 +3,13 @@
|
||||||
#
|
#
|
||||||
# Usage :
|
# Usage :
|
||||||
# cp .env.example .env
|
# cp .env.example .env
|
||||||
# Editer .env (gitignore) avec les valeurs reelles.
|
# docker compose up -d
|
||||||
#
|
#
|
||||||
# Audience :
|
# Ce template fonctionne EN LOCAL tel quel (valeurs dev) : la stack est joignable
|
||||||
# Destine a l'auteur, au jury et aux contributeurs futurs.
|
# sur http://kiosk.localhost:8080 (borne) et http://admin.localhost:8080 (admin).
|
||||||
#
|
# Le deploiement derriere un reverse proxy (Traefik) se fait via l'overlay
|
||||||
# Modele de deploiement :
|
# docker-compose.prod.yml + les variables du bloc "Deploiement prod" en fin de
|
||||||
# Ce projet tourne sur serveur derriere un reverse proxy Traefik. Il n'y a
|
# fichier. En prod : changer les mots de passe, APP_DEBUG=false, vrais FQDN.
|
||||||
# pas de binding de ports hote : l'acces se fait uniquement via les FQDN
|
|
||||||
# configures ci-dessous et routes par Traefik (reseau admin_proxy).
|
|
||||||
# Les distinctions dev / staging / prod se font par FQDN distincts
|
|
||||||
# (ex : .dev.acadenice.fr vs .acadenice.fr) et par .env dedie.
|
|
||||||
#
|
#
|
||||||
|
|
||||||
# ===================================================================
|
# ===================================================================
|
||||||
|
|
@ -24,27 +20,30 @@ APP_ENV=dev # dev | staging | prod
|
||||||
APP_DEBUG=true # true en dev, false en prod
|
APP_DEBUG=true # true en dev, false en prod
|
||||||
APP_TIMEZONE=Europe/Paris
|
APP_TIMEZONE=Europe/Paris
|
||||||
|
|
||||||
# URL publique de la borne (Bloc 1), doit pointer vers le FQDN Traefik.
|
# Port hote publie par wakdo-web (acces local). Change si 8080 est pris.
|
||||||
# Placeholder example.com (RFC 2606) - a remplacer par le FQDN reel.
|
HTTP_PORT=8080
|
||||||
APP_URL_KIOSK=https://kiosk.example.com
|
|
||||||
|
|
||||||
# URL publique du back-office + API (Bloc 2).
|
# Hostnames des deux vhosts Apache (ServerName). En local : *.localhost resout
|
||||||
# Placeholder example.com (RFC 2606) - a remplacer par le FQDN reel.
|
# vers 127.0.0.1 nativement. En prod : les vrais FQDN (voir bloc prod en bas).
|
||||||
APP_URL_ADMIN=https://admin.example.com
|
APP_HOST_KIOSK=kiosk.localhost
|
||||||
|
APP_HOST_ADMIN=admin.localhost
|
||||||
|
|
||||||
|
# URLs publiques (consommees par l'app). En local = les hostnames sur HTTP_PORT.
|
||||||
|
APP_URL_KIOSK=http://kiosk.localhost:8080
|
||||||
|
APP_URL_ADMIN=http://admin.localhost:8080
|
||||||
|
|
||||||
# ===================================================================
|
# ===================================================================
|
||||||
# Base de donnees (MariaDB)
|
# Base de donnees (MariaDB)
|
||||||
# ===================================================================
|
# ===================================================================
|
||||||
# Valeurs ci-dessous = PLACEHOLDERS. Remplacer par des mots de passe forts.
|
# Valeurs dev ci-dessous : OK en local. EN PROD : mots de passe forts.
|
||||||
# Pas accessible depuis l'exterieur : le service wakdo-db est sur le reseau
|
# wakdo-db est sur le reseau interne, aucun port expose a l'hote.
|
||||||
# interne uniquement, aucun port exposé a l'hote.
|
|
||||||
|
|
||||||
DB_HOST=wakdo-db # nom du service docker-compose
|
DB_HOST=wakdo-db # nom du service docker-compose
|
||||||
DB_PORT=3306
|
DB_PORT=3306
|
||||||
DB_NAME=wakdo
|
DB_NAME=wakdo
|
||||||
DB_USER=wakdo
|
DB_USER=wakdo
|
||||||
DB_PASSWORD=change_me_strong_password
|
DB_PASSWORD=wakdo_dev_password
|
||||||
DB_ROOT_PASSWORD=change_me_root_password
|
DB_ROOT_PASSWORD=wakdo_dev_root_password
|
||||||
|
|
||||||
# ===================================================================
|
# ===================================================================
|
||||||
# Sessions
|
# Sessions
|
||||||
|
|
@ -58,18 +57,15 @@ SESSION_NAME=WAKDO_SID # nom du cookie (evite PHPSESSID)
|
||||||
# Securite
|
# Securite
|
||||||
# ===================================================================
|
# ===================================================================
|
||||||
|
|
||||||
# Origine autorisee pour les requetes CORS de l'API.
|
# Origine autorisee pour les requetes CORS de l'API. Doit correspondre
|
||||||
# Doit correspondre exactement a APP_URL_KIOSK (pas de wildcard).
|
# exactement a APP_URL_KIOSK (pas de wildcard).
|
||||||
CORS_ALLOWED_ORIGIN=https://kiosk.example.com
|
CORS_ALLOWED_ORIGIN=http://kiosk.localhost:8080
|
||||||
|
|
||||||
# Algorithme de hashage : argon2id, FIXE dans le code (App\Auth\PasswordHasher),
|
# Algorithme de hashage : argon2id, FIXE dans le code (App\Auth\PasswordHasher),
|
||||||
# choix security-by-design non configurable (pas de bascule runtime vers un algo
|
# choix security-by-design non configurable. Seuls les COUTS ci-dessous sont reglables.
|
||||||
# plus faible). Seuls les COUTS ci-dessous sont reglables.
|
|
||||||
|
|
||||||
# Parametres de cout argon2id (password_hash options).
|
# Parametres de cout argon2id (password_hash options). Defauts alignes OWASP
|
||||||
# Defauts alignes sur les recommandations OWASP Password Storage Cheat Sheet
|
# (memoire >= 19 MiB, >= 2 iterations). Servent aussi au hash du PIN equipier.
|
||||||
# (memoire >= 19 MiB, >= 2 iterations). 65536 KiB = 64 MiB, marge confortable.
|
|
||||||
# Ces valeurs servent aussi au hash du PIN equipier (pin_hash, actions sensibles).
|
|
||||||
ARGON2_MEMORY_COST=65536 # KiB (64 MiB)
|
ARGON2_MEMORY_COST=65536 # KiB (64 MiB)
|
||||||
ARGON2_TIME_COST=4 # nombre d'iterations
|
ARGON2_TIME_COST=4 # nombre d'iterations
|
||||||
ARGON2_THREADS=1 # parallelisme (1 = portable, deterministe)
|
ARGON2_THREADS=1 # parallelisme (1 = portable, deterministe)
|
||||||
|
|
@ -77,49 +73,38 @@ ARGON2_THREADS=1 # parallelisme (1 = portable, determini
|
||||||
# ===================================================================
|
# ===================================================================
|
||||||
# Anti brute-force - throttling de connexion (security-by-design)
|
# Anti brute-force - throttling de connexion (security-by-design)
|
||||||
# ===================================================================
|
# ===================================================================
|
||||||
# Deux gardes complementaires (cf. docs/merise/mld.md 4.21 + PROJECT_CONTEXT 19) :
|
# Deux gardes : par compte (user.failed_login_attempts / lockout_until) et par IP
|
||||||
# 1. par compte : colonnes user.failed_login_attempts / user.lockout_until
|
# (table login_throttle). Backoff degressif, pas de lock definitif.
|
||||||
# 2. par IP source : table login_throttle (entite 21)
|
|
||||||
# Backoff degressif (pas de lock definitif) : evite le DoS sur compte legitime.
|
|
||||||
|
|
||||||
# Compteur par compte : nombre d'echecs avant declenchement du backoff.
|
|
||||||
ACCOUNT_LOCKOUT_THRESHOLD=5
|
ACCOUNT_LOCKOUT_THRESHOLD=5
|
||||||
# Duree de base du backoff (secondes). Croit de facon degressive a chaque
|
|
||||||
# palier d'echecs supplementaires (ex : 60 -> 300 -> 900).
|
|
||||||
ACCOUNT_LOCKOUT_BASE_SECONDS=60
|
ACCOUNT_LOCKOUT_BASE_SECONDS=60
|
||||||
ACCOUNT_LOCKOUT_MAX_SECONDS=900 # plafond du backoff (15 min)
|
ACCOUNT_LOCKOUT_MAX_SECONDS=900 # plafond du backoff (15 min)
|
||||||
|
|
||||||
# Gate par IP : fenetre glissante et plafond de tentatives sur cette fenetre.
|
|
||||||
IP_THROTTLE_WINDOW_SECONDS=900 # 15 min
|
IP_THROTTLE_WINDOW_SECONDS=900 # 15 min
|
||||||
IP_THROTTLE_MAX_ATTEMPTS=20 # par IP sur la fenetre
|
IP_THROTTLE_MAX_ATTEMPTS=20 # par IP sur la fenetre
|
||||||
|
|
||||||
# PIN equipier pour actions sensibles (annulation, override). Chiffres uniquement,
|
# PIN equipier pour actions sensibles. Chiffres, bornes min ET max (RG-T18).
|
||||||
# bornes min ET max (RG-T18 : validation serveur + longueur bornee).
|
|
||||||
STAFF_PIN_MIN_LENGTH=4
|
STAFF_PIN_MIN_LENGTH=4
|
||||||
STAFF_PIN_MAX_LENGTH=12
|
STAFF_PIN_MAX_LENGTH=12
|
||||||
|
|
||||||
# Throttle du PIN d'action sensible (RG-T22) - compteurs SEPARES du login : la
|
# Throttle du PIN d'action sensible (RG-T22) - compteurs SEPARES du login,
|
||||||
# dimension est l'utilisateur AGISSANT (session), pas l'email cible ni l'IP. Bornes
|
# dimension = utilisateur agissant. Bornes plus permissives que le login.
|
||||||
# volontairement plus permissives que le login (controle de dissuasion) : ne pas
|
PIN_THROTTLE_THRESHOLD=5
|
||||||
# bloquer un manager en plein rush sur quelques fautes de frappe.
|
PIN_THROTTLE_BASE_SECONDS=30
|
||||||
PIN_THROTTLE_THRESHOLD=5 # echecs avant le backoff (par acteur)
|
PIN_THROTTLE_MAX_SECONDS=300
|
||||||
PIN_THROTTLE_BASE_SECONDS=30 # 1er palier (vs 60 au login)
|
PIN_THROTTLE_WINDOW_SECONDS=900
|
||||||
PIN_THROTTLE_MAX_SECONDS=300 # plafond du backoff (5 min, vs 900 au login)
|
|
||||||
PIN_THROTTLE_WINDOW_SECONDS=900 # fenetre glissante (15 min)
|
|
||||||
|
|
||||||
# Expiration du token de reinitialisation de mot de passe (secondes).
|
# Expiration du token de reinitialisation de mot de passe (secondes).
|
||||||
PASSWORD_RESET_TTL=3600 # 1h
|
PASSWORD_RESET_TTL=3600 # 1h
|
||||||
|
|
||||||
# ===================================================================
|
# ===================================================================
|
||||||
# Retention des donnees (RGPD - minimisation et limitation de conservation)
|
# Retention des donnees (RGPD)
|
||||||
# ===================================================================
|
# ===================================================================
|
||||||
# Purges executees par le service cron (docker/cron/crontab).
|
# Purges executees par le service cron (docker/cron/crontab).
|
||||||
# Justification documentee : interet legitime / obligations probatoires.
|
|
||||||
|
|
||||||
AUDIT_LOG_RETENTION_DAYS=365 # journal d'audit ~12 mois
|
AUDIT_LOG_RETENTION_DAYS=365 # journal d'audit ~12 mois
|
||||||
THROTTLE_PURGE_AFTER_HOURS=24 # login_throttle : lignes sans lockout actif > 24h
|
THROTTLE_PURGE_AFTER_HOURS=24 # login_throttle : lignes sans lockout actif > 24h
|
||||||
ORDER_RETENTION_DAYS=1095 # commandes (historique/stats) ~3 ans
|
ORDER_RETENTION_DAYS=1095 # commandes (historique/stats) ~3 ans
|
||||||
# Purge des sessions expirees : deja geree par le cron */15 (voir crontab).
|
|
||||||
|
|
||||||
# ===================================================================
|
# ===================================================================
|
||||||
# Upload images produits
|
# Upload images produits
|
||||||
|
|
@ -131,34 +116,18 @@ UPLOAD_ALLOWED_MIME=image/jpeg,image/png,image/webp
|
||||||
# ===================================================================
|
# ===================================================================
|
||||||
# Cron (fenetre de maintenance 01h30 - 09h30)
|
# Cron (fenetre de maintenance 01h30 - 09h30)
|
||||||
# ===================================================================
|
# ===================================================================
|
||||||
# Les jobs sont definis dans docker/cron/crontab. Ici uniquement le TZ.
|
|
||||||
|
|
||||||
CRON_TIMEZONE=Europe/Paris
|
CRON_TIMEZONE=Europe/Paris
|
||||||
|
|
||||||
# ===================================================================
|
# ===================================================================
|
||||||
# Exposition via Traefik
|
# Deploiement prod (overlay docker-compose.prod.yml) - OPTIONNEL
|
||||||
# ===================================================================
|
# ===================================================================
|
||||||
# FQDN consommes par les labels docker-compose.yml pour generer les routes
|
# A ignorer pour un usage local. Necessaire UNIQUEMENT derriere un reverse proxy
|
||||||
# Traefik et les certificats TLS (Traefik gere le resolver par defaut).
|
# Traefik, avec : docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
|
||||||
# Le Traefik de l'hote prend en charge Let's Encrypt automatiquement.
|
|
||||||
|
|
||||||
TRAEFIK_DOMAIN_KIOSK=kiosk.example.com
|
|
||||||
TRAEFIK_DOMAIN_ADMIN=admin.example.com
|
|
||||||
|
|
||||||
# ===================================================================
|
|
||||||
# Reseau Docker externe du reverse proxy
|
|
||||||
# ===================================================================
|
|
||||||
# Nom du reseau Docker externe auquel le service web doit se connecter
|
|
||||||
# pour etre expose par le reverse proxy de l'hote.
|
|
||||||
#
|
#
|
||||||
# Adapter selon votre infrastructure. Valeurs courantes :
|
# En prod, surcharger aussi : APP_ENV=prod, APP_DEBUG=false, mots de passe forts,
|
||||||
# traefik_proxy - convention neutre (placeholder)
|
# et APP_HOST_*/APP_URL_*/CORS_ALLOWED_ORIGIN avec les vrais FQDN HTTPS.
|
||||||
# traefik_public - convention doc Traefik
|
|
||||||
# traefik - setups simples
|
|
||||||
# proxy - autre convention frequente
|
|
||||||
#
|
#
|
||||||
# Le reseau doit exister AVANT 'docker compose up' (cree par votre stack de
|
# Nom du reseau Docker externe partage avec le Traefik de l'hote (doit exister
|
||||||
# reverse proxy, ou manuellement : docker network create <nom>). Sinon
|
# AVANT le up : cree par la stack Traefik, ou `docker network create <nom>`).
|
||||||
# 'docker compose up' echoue avec une erreur sur le reseau externe introuvable.
|
REVERSE_PROXY_NETWORK=admin_proxy
|
||||||
|
|
||||||
REVERSE_PROXY_NETWORK=traefik_proxy
|
|
||||||
|
|
|
||||||
5
.gitignore
vendored
5
.gitignore
vendored
|
|
@ -5,6 +5,11 @@
|
||||||
*.pem
|
*.pem
|
||||||
*.key
|
*.key
|
||||||
|
|
||||||
|
# Compose de production (propre a chaque hote : Traefik/reverse proxy, FQDN).
|
||||||
|
# Le repo ne ship que docker-compose.yml (standalone, local). Chaque hote derriere
|
||||||
|
# un proxy maintient son propre docker-compose.prod.yml (hors versionnement).
|
||||||
|
docker-compose.prod.yml
|
||||||
|
|
||||||
# === BYAN — plateforme (moteur), masquee ===
|
# === BYAN — plateforme (moteur), masquee ===
|
||||||
# Le code moteur des agents n'est pas part du rendu RNCP.
|
# Le code moteur des agents n'est pas part du rendu RNCP.
|
||||||
# La methodologie appliquee (CLAUDE.md + rules + hooks) reste dans .claude/
|
# La methodologie appliquee (CLAUDE.md + rules + hooks) reste dans .claude/
|
||||||
|
|
|
||||||
77
README.md
77
README.md
|
|
@ -89,80 +89,41 @@ Reseaux, volumes, services et decoupage reseau interne / reseau proxy : voir `do
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Quickstart
|
## Quickstart (local)
|
||||||
|
|
||||||
Ce projet tourne **sur serveur derriere un reverse proxy Traefik** : pas de binding de ports hote, pas d'acces `localhost`. L'acces public se fait par FQDN HTTPS (TLS gere automatiquement par Traefik). Les environnements `dev`, `staging` et `prod` se distinguent par des FQDN et des fichiers `.env` separes.
|
|
||||||
|
|
||||||
### Prerequis sur l'hote
|
|
||||||
|
|
||||||
1. Docker Engine + docker compose v2 (voir ci-dessous)
|
|
||||||
2. Un reverse proxy Traefik deja en place, avec un reseau Docker externe dedie. Le **nom du reseau** est configurable via la variable `REVERSE_PROXY_NETWORK` du `.env` (defaut : `admin_proxy` — convention de l'auteur). A adapter a votre infrastructure.
|
|
||||||
3. Les FQDN cibles pointent en DNS vers l'hote
|
|
||||||
|
|
||||||
### Sur un hote deja equipe (Docker + Traefik)
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone git@github.com:AcadeNice/wakdo_corentin.git
|
git clone git@github.com:AcadeNice/wakdo_corentin.git
|
||||||
cd wakdo_corentin
|
cd wakdo_corentin
|
||||||
cp .env.example .env
|
cp .env.example .env
|
||||||
# Editer .env : DB_PASSWORD, DB_ROOT_PASSWORD, APP_URL_*, TRAEFIK_DOMAIN_*
|
|
||||||
docker compose up -d
|
docker compose up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
> **Attention au `.env` pre-existant.** Si un fichier `.env` existe deja a la racine (tooling externe, autre plateforme installee dans le meme repertoire), **ne pas faire** `cp .env.example .env` — cela ecraserait les variables existantes. Faire un **merge manuel** a la place : ajouter les variables manquantes du template dans le `.env` actuel. Les prefixes de variables de ce projet (`APP_`, `DB_`, `SESSION_`, `CORS_`, `UPLOAD_`, `CRON_`, `TRAEFIK_`, `REVERSE_PROXY_`) sont disjoints de ceux utilises par des outils tiers courants, donc la cohabitation est safe.
|
Une seule commande lance la stack complete (Cr 7.c.4) : le service one-shot
|
||||||
|
`wakdo-migrate` applique les migrations puis le seed (idempotents, tables de suivi
|
||||||
|
`schema_migrations` / `seeds_applied`) avant que l'app ne serve. Ensuite :
|
||||||
|
|
||||||
Critere RNCP Cr 7.c.4 couvert : une seule commande (`docker compose up -d`) lance la
|
- Borne : http://kiosk.localhost:8080
|
||||||
stack complete. Le service one-shot `wakdo-migrate` applique le schema (migrations)
|
- Admin + API : http://admin.localhost:8080
|
||||||
puis les donnees de reference (seed) avant que l'app ne serve ; `wakdo-app`/`wakdo-web`
|
|
||||||
attendent sa completion (`depends_on: service_completed_successfully`). Migrations et
|
|
||||||
seed sont idempotents (tables de suivi `schema_migrations` / `seeds_applied`).
|
|
||||||
Detail : `docs/journal/2026-06-17--makefile-to-compose-migrate.md`.
|
|
||||||
|
|
||||||
Services accessibles apres `docker compose up -d` :
|
`*.localhost` resout vers `127.0.0.1` nativement ; changer le port via `HTTP_PORT`
|
||||||
- Borne : la valeur de `TRAEFIK_DOMAIN_KIOSK` dans `.env`
|
dans `.env`. Le `.env.example` fonctionne tel quel en local (valeurs dev).
|
||||||
- Admin + API : la valeur de `TRAEFIK_DOMAIN_ADMIN` dans `.env`
|
|
||||||
|
|
||||||
### Installation Docker sur un hote neuf (Debian / Ubuntu)
|
Docker non installe ? Voir https://docs.docker.com/engine/install/
|
||||||
|
|
||||||
Procedure officielle detaillee : `https://docs.docker.com/engine/install/` (selectionner la distribution). Resume pour Debian stable :
|
### Deploiement prod (derriere un reverse proxy Traefik)
|
||||||
|
|
||||||
|
Le repo ne ship que `docker-compose.yml` (standalone). En production derriere un
|
||||||
|
reverse proxy, chaque hote maintient son **propre `docker-compose.prod.yml`**
|
||||||
|
(gitignore, hors repo, comme `.env`) : meme stack, mais exposee via Traefik (reseau
|
||||||
|
externe + labels TLS) au lieu d'un port hote.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo apt update
|
docker compose -f docker-compose.prod.yml up -d
|
||||||
sudo apt install -y ca-certificates curl
|
|
||||||
sudo install -m 0755 -d /etc/apt/keyrings
|
|
||||||
sudo curl -fsSL https://download.docker.com/linux/debian/gpg \
|
|
||||||
-o /etc/apt/keyrings/docker.asc
|
|
||||||
sudo chmod a+r /etc/apt/keyrings/docker.asc
|
|
||||||
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \
|
|
||||||
https://download.docker.com/linux/debian \
|
|
||||||
$(. /etc/os-release && echo $VERSION_CODENAME) stable" \
|
|
||||||
| sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
|
||||||
sudo apt update
|
|
||||||
sudo apt install -y docker-ce docker-ce-cli containerd.io \
|
|
||||||
docker-buildx-plugin docker-compose-plugin
|
|
||||||
sudo usermod -aG docker $USER
|
|
||||||
# Fermer et rouvrir la session pour activer le groupe docker
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Reseau externe du reverse proxy
|
Avec un `.env` adapte : `APP_ENV=prod`, `APP_DEBUG=false`, mots de passe forts,
|
||||||
|
`APP_HOST_*` / `APP_URL_*` / `CORS_ALLOWED_ORIGIN` en vrais FQDN HTTPS, et
|
||||||
Le `docker-compose.yml` attend un reseau Docker externe deja existant sur l'hote, dont le nom est donne par la variable `REVERSE_PROXY_NETWORK` (defaut : `admin_proxy`).
|
`REVERSE_PROXY_NETWORK` = reseau Docker du Traefik de l'hote (doit exister avant le up).
|
||||||
|
|
||||||
Si vous avez deja un Traefik en place, ce reseau a generalement ete cree par son propre stack. Adaptez la variable `REVERSE_PROXY_NETWORK` dans votre `.env` au nom utilise par votre proxy. Sinon, creez-le manuellement :
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker network create mon_reseau_proxy
|
|
||||||
# puis dans .env :
|
|
||||||
# REVERSE_PROXY_NETWORK=mon_reseau_proxy
|
|
||||||
```
|
|
||||||
|
|
||||||
Avant le premier `docker compose up`, s'assurer que le reseau existe. Verification rapide :
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker network inspect "$(grep ^REVERSE_PROXY_NETWORK .env | cut -d= -f2)"
|
|
||||||
```
|
|
||||||
|
|
||||||
Si la commande retourne une erreur, soit adapter `REVERSE_PROXY_NETWORK` au nom du reseau utilise par votre proxy, soit creer le reseau manuellement (le reseau externe doit exister avant `docker compose up`).
|
|
||||||
|
|
||||||
*Section mise a jour au fil de l'implementation (migrations reelles, seed, CI/CD deploiement).*
|
*Section mise a jour au fil de l'implementation (migrations reelles, seed, CI/CD deploiement).*
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,87 +1,19 @@
|
||||||
#
|
|
||||||
# Wakdo - orchestration des 4 services de la stack (Bloc 5 DevOps, Cr 7.c.3 / 7.c.4).
|
|
||||||
#
|
|
||||||
# Services :
|
|
||||||
# wakdo-web : Apache httpd, reverse proxy FastCGI -> wakdo-app, expose 80 via Traefik
|
|
||||||
# wakdo-app : PHP-FPM 8.3, execute le code PHP back-office + API
|
|
||||||
# wakdo-db : MariaDB 11.4, persistance des donnees metier
|
|
||||||
# wakdo-cron : Alpine + dcron, backups nocturnes et taches planifiees
|
|
||||||
#
|
|
||||||
# Reseaux :
|
|
||||||
# default (nom = wakdo_internal) : bridge interne pour l'inter-service,
|
|
||||||
# non expose a l'hote. app/db/cron ne sont PAS joignables publiquement.
|
|
||||||
# <REVERSE_PROXY_NETWORK> : reseau externe (ex. traefik_proxy) partage
|
|
||||||
# avec le Traefik de l'hote. Seul wakdo-web y est attache.
|
|
||||||
#
|
|
||||||
# Volumes :
|
|
||||||
# wakdo_db_data : named volume pour /var/lib/mysql (persistance BDD)
|
|
||||||
# wakdo_uploads : named volume pour les uploads produits back-office
|
|
||||||
# ./var/backups : bind-mount lecture-ecriture pour les dumps SQL
|
|
||||||
#
|
|
||||||
# Variables d'env consommees depuis .env : docker compose lit automatiquement le
|
|
||||||
# fichier .env a la racine et fait l'expansion des ${...} ci-dessous.
|
|
||||||
#
|
|
||||||
# Persistance : `docker compose down` preserve les named volumes ; seul
|
|
||||||
# `docker compose down -v` supprime les donnees.
|
|
||||||
#
|
|
||||||
|
|
||||||
name: wakdo
|
name: wakdo
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
# Reseau interne : isolement des services applicatifs.
|
|
||||||
# wakdo-app, wakdo-db et wakdo-cron n'y sont accessibles que via les autres
|
|
||||||
# conteneurs de la stack. Aucun port hote expose.
|
|
||||||
wakdo_internal:
|
wakdo_internal:
|
||||||
driver: bridge
|
driver: bridge
|
||||||
internal: false
|
|
||||||
# internal: false (par defaut) car wakdo-app et wakdo-cron ont besoin
|
|
||||||
# de sortir sur internet (pour telecharger des packages au build et pour
|
|
||||||
# de potentiels appels API externes futurs). L'isolation vient du fait
|
|
||||||
# qu'aucun port hote n'est binde ici.
|
|
||||||
#
|
|
||||||
# Subnet explicite (RFC 1918) : l'auto-allocateur Docker du daemon hote
|
|
||||||
# est sature (15 /16 + 15 /20 deja alloues par d'autres stacks), il ne
|
|
||||||
# peut plus creer de reseau bridge sans subnet explicite. 192.168.148.0/24
|
|
||||||
# est dans le gap libre 192.168.144-159 (256 IP, largement suffisant pour
|
|
||||||
# 4 services), aucune collision avec les /24 acquagest voisins (150/154/
|
|
||||||
# 155/157). Choix defendable : right-sizing + isolation des fluctuations
|
|
||||||
# d'allocation auto sur cet hote mutualise.
|
|
||||||
ipam:
|
|
||||||
driver: default
|
|
||||||
config:
|
|
||||||
- subnet: 192.168.148.0/24
|
|
||||||
|
|
||||||
# Reseau du reverse proxy (Traefik) pre-existant sur l'hote.
|
|
||||||
# Son nom est configurable via REVERSE_PROXY_NETWORK dans .env pour
|
|
||||||
# supporter differents setups (traefik_proxy, traefik_public, proxy, ...).
|
|
||||||
reverse_proxy:
|
|
||||||
name: ${REVERSE_PROXY_NETWORK}
|
|
||||||
external: true
|
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
wakdo_db_data:
|
wakdo_db_data:
|
||||||
# Named volume MariaDB. Permissions gerees par Docker (UID mysql=999
|
|
||||||
# dans le conteneur), zero souci cote hote. Survit a `docker compose down`.
|
|
||||||
# Pour remise a zero : `docker compose down -v` (destructif : supprime les volumes).
|
|
||||||
|
|
||||||
wakdo_uploads:
|
wakdo_uploads:
|
||||||
# Images produits uploadees par les equipiers depuis le back-office.
|
|
||||||
# Named volume pour les memes raisons que wakdo_db_data : permissions
|
|
||||||
# propres (www-data UID 82 en Alpine) et pas de pollution du repo git
|
|
||||||
# par des binaires.
|
|
||||||
|
|
||||||
services:
|
services:
|
||||||
|
|
||||||
# =======================================================================
|
|
||||||
# wakdo-db : MariaDB 11.4 LTS
|
|
||||||
# =======================================================================
|
|
||||||
wakdo-db:
|
wakdo-db:
|
||||||
image: mariadb:11.4
|
image: mariadb:11.4
|
||||||
container_name: wakdo-db
|
container_name: wakdo-db
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
# Variables d'env d'initialisation (ne s'appliquent qu'au premier demarrage
|
|
||||||
# sur volume vide - voir docs/notes/docker-volumes-vs-bind-mounts.md).
|
|
||||||
environment:
|
environment:
|
||||||
MARIADB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
|
MARIADB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
|
||||||
MARIADB_DATABASE: ${DB_NAME}
|
MARIADB_DATABASE: ${DB_NAME}
|
||||||
|
|
@ -89,22 +21,11 @@ services:
|
||||||
MARIADB_PASSWORD: ${DB_PASSWORD}
|
MARIADB_PASSWORD: ${DB_PASSWORD}
|
||||||
MARIADB_AUTO_UPGRADE: "1"
|
MARIADB_AUTO_UPGRADE: "1"
|
||||||
TZ: ${APP_TIMEZONE:-Europe/Paris}
|
TZ: ${APP_TIMEZONE:-Europe/Paris}
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
- wakdo_db_data:/var/lib/mysql
|
- wakdo_db_data:/var/lib/mysql
|
||||||
# Scripts d'init MariaDB, executes UNIQUEMENT au premier demarrage sur
|
|
||||||
# volume vierge : durcit le privilege du user applicatif (moindre
|
|
||||||
# privilege, db/init/10-scope-app-user.sh). Lecture seule.
|
|
||||||
- ./db/init:/docker-entrypoint-initdb.d:ro
|
- ./db/init:/docker-entrypoint-initdb.d:ro
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
- wakdo_internal
|
- wakdo_internal
|
||||||
|
|
||||||
# Pas de ports exposes a l'hote : seuls wakdo-app et wakdo-cron peuvent
|
|
||||||
# joindre wakdo-db:3306 via le reseau interne.
|
|
||||||
|
|
||||||
# Healthcheck officiel fourni par l'image mariadb : le script bundled
|
|
||||||
# healthcheck.sh teste la connexion et l'init innodb.
|
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
|
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
|
||||||
interval: 10s
|
interval: 10s
|
||||||
|
|
@ -112,48 +33,30 @@ services:
|
||||||
retries: 6
|
retries: 6
|
||||||
start_period: 30s
|
start_period: 30s
|
||||||
|
|
||||||
# =======================================================================
|
|
||||||
# wakdo-migrate : service ONE-SHOT (migrations + seed idempotents)
|
|
||||||
# =======================================================================
|
|
||||||
# Tourne une fois apres que wakdo-db soit healthy, applique le schema puis les
|
|
||||||
# donnees de reference (idempotent via schema_migrations / seeds_applied), et
|
|
||||||
# sort. app/web attendent sa COMPLETION : `docker compose up` rend ainsi la stack
|
|
||||||
# complete + utilisable en UNE commande, sans dependance a l'hote (Cr 7.c.4).
|
|
||||||
wakdo-migrate:
|
wakdo-migrate:
|
||||||
image: mariadb:11.4
|
image: mariadb:11.4
|
||||||
container_name: wakdo-migrate
|
container_name: wakdo-migrate
|
||||||
restart: "no"
|
restart: "no"
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
DB_HOST: ${DB_HOST}
|
DB_HOST: ${DB_HOST}
|
||||||
DB_PORT: ${DB_PORT}
|
DB_PORT: ${DB_PORT}
|
||||||
DB_NAME: ${DB_NAME}
|
DB_NAME: ${DB_NAME}
|
||||||
# Root : migrations = DDL, seeds = INSERT de reference.
|
|
||||||
DB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
|
DB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
# migrations + seeds + le runner, en lecture seule.
|
|
||||||
- ./db:/db:ro
|
- ./db:/db:ro
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
- wakdo_internal
|
- wakdo_internal
|
||||||
|
|
||||||
depends_on:
|
depends_on:
|
||||||
wakdo-db:
|
wakdo-db:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
|
||||||
entrypoint: ["bash", "/db/migrate-container.sh"]
|
entrypoint: ["bash", "/db/migrate-container.sh"]
|
||||||
|
|
||||||
# =======================================================================
|
|
||||||
# wakdo-app : PHP-FPM 8.3 (execute le code back-office + API)
|
|
||||||
# =======================================================================
|
|
||||||
wakdo-app:
|
wakdo-app:
|
||||||
build:
|
build:
|
||||||
context: ./docker/php-fpm
|
context: ./docker/php-fpm
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
container_name: wakdo-app
|
container_name: wakdo-app
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
APP_ENV: ${APP_ENV}
|
APP_ENV: ${APP_ENV}
|
||||||
APP_DEBUG: ${APP_DEBUG}
|
APP_DEBUG: ${APP_DEBUG}
|
||||||
|
|
@ -169,80 +72,50 @@ services:
|
||||||
SESSION_LIFETIME_ABSOLUTE: ${SESSION_LIFETIME_ABSOLUTE}
|
SESSION_LIFETIME_ABSOLUTE: ${SESSION_LIFETIME_ABSOLUTE}
|
||||||
SESSION_NAME: ${SESSION_NAME}
|
SESSION_NAME: ${SESSION_NAME}
|
||||||
CORS_ALLOWED_ORIGIN: ${CORS_ALLOWED_ORIGIN}
|
CORS_ALLOWED_ORIGIN: ${CORS_ALLOWED_ORIGIN}
|
||||||
# Cout argon2id (password_hash) : aligne sur .env.example / OWASP. Sert au
|
|
||||||
# hash du mot de passe ET du PIN equipier (actions sensibles, P3).
|
|
||||||
ARGON2_MEMORY_COST: ${ARGON2_MEMORY_COST}
|
ARGON2_MEMORY_COST: ${ARGON2_MEMORY_COST}
|
||||||
ARGON2_TIME_COST: ${ARGON2_TIME_COST}
|
ARGON2_TIME_COST: ${ARGON2_TIME_COST}
|
||||||
ARGON2_THREADS: ${ARGON2_THREADS}
|
ARGON2_THREADS: ${ARGON2_THREADS}
|
||||||
# Anti brute-force : backoff degressif par compte (user.lockout_until) et
|
|
||||||
# par IP source (table login_throttle). Voir mlt.md 12.1 RG-8/RG-9.
|
|
||||||
ACCOUNT_LOCKOUT_THRESHOLD: ${ACCOUNT_LOCKOUT_THRESHOLD}
|
ACCOUNT_LOCKOUT_THRESHOLD: ${ACCOUNT_LOCKOUT_THRESHOLD}
|
||||||
ACCOUNT_LOCKOUT_BASE_SECONDS: ${ACCOUNT_LOCKOUT_BASE_SECONDS}
|
ACCOUNT_LOCKOUT_BASE_SECONDS: ${ACCOUNT_LOCKOUT_BASE_SECONDS}
|
||||||
ACCOUNT_LOCKOUT_MAX_SECONDS: ${ACCOUNT_LOCKOUT_MAX_SECONDS}
|
ACCOUNT_LOCKOUT_MAX_SECONDS: ${ACCOUNT_LOCKOUT_MAX_SECONDS}
|
||||||
IP_THROTTLE_WINDOW_SECONDS: ${IP_THROTTLE_WINDOW_SECONDS}
|
IP_THROTTLE_WINDOW_SECONDS: ${IP_THROTTLE_WINDOW_SECONDS}
|
||||||
IP_THROTTLE_MAX_ATTEMPTS: ${IP_THROTTLE_MAX_ATTEMPTS}
|
IP_THROTTLE_MAX_ATTEMPTS: ${IP_THROTTLE_MAX_ATTEMPTS}
|
||||||
# Bornes du PIN equipier (actions sensibles, P3) : longueur min ET max.
|
|
||||||
STAFF_PIN_MIN_LENGTH: ${STAFF_PIN_MIN_LENGTH}
|
STAFF_PIN_MIN_LENGTH: ${STAFF_PIN_MIN_LENGTH}
|
||||||
STAFF_PIN_MAX_LENGTH: ${STAFF_PIN_MAX_LENGTH}
|
STAFF_PIN_MAX_LENGTH: ${STAFF_PIN_MAX_LENGTH}
|
||||||
# Throttle du PIN d'action sensible (RG-T22) : compteurs SEPARES du login.
|
|
||||||
PIN_THROTTLE_THRESHOLD: ${PIN_THROTTLE_THRESHOLD}
|
PIN_THROTTLE_THRESHOLD: ${PIN_THROTTLE_THRESHOLD}
|
||||||
PIN_THROTTLE_BASE_SECONDS: ${PIN_THROTTLE_BASE_SECONDS}
|
PIN_THROTTLE_BASE_SECONDS: ${PIN_THROTTLE_BASE_SECONDS}
|
||||||
PIN_THROTTLE_MAX_SECONDS: ${PIN_THROTTLE_MAX_SECONDS}
|
PIN_THROTTLE_MAX_SECONDS: ${PIN_THROTTLE_MAX_SECONDS}
|
||||||
PIN_THROTTLE_WINDOW_SECONDS: ${PIN_THROTTLE_WINDOW_SECONDS}
|
PIN_THROTTLE_WINDOW_SECONDS: ${PIN_THROTTLE_WINDOW_SECONDS}
|
||||||
# Expiration du token de reinitialisation de mot de passe (mlt.md 12.3).
|
|
||||||
PASSWORD_RESET_TTL: ${PASSWORD_RESET_TTL}
|
PASSWORD_RESET_TTL: ${PASSWORD_RESET_TTL}
|
||||||
UPLOAD_MAX_SIZE_MB: ${UPLOAD_MAX_SIZE_MB}
|
UPLOAD_MAX_SIZE_MB: ${UPLOAD_MAX_SIZE_MB}
|
||||||
UPLOAD_ALLOWED_MIME: ${UPLOAD_ALLOWED_MIME}
|
UPLOAD_ALLOWED_MIME: ${UPLOAD_ALLOWED_MIME}
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
# Bind-mount du code source pour le hot-reload en dev.
|
|
||||||
# En prod, cette ligne est remplacee par un COPY dans l'image
|
|
||||||
# via docker-compose.prod.yml (override a venir en P7).
|
|
||||||
- ./src:/var/www/html
|
- ./src:/var/www/html
|
||||||
|
|
||||||
# Named volume pour les uploads, plus specifique que le bind-mount
|
|
||||||
# parent : les uploads ne vont pas dans ./src, ils restent dans le
|
|
||||||
# volume Docker et survivent aux `docker compose down`.
|
|
||||||
- wakdo_uploads:/var/www/html/public/uploads
|
- wakdo_uploads:/var/www/html/public/uploads
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
- wakdo_internal
|
- wakdo_internal
|
||||||
|
|
||||||
depends_on:
|
depends_on:
|
||||||
# Le schema + les donnees de reference sont en place AVANT que l'app serve.
|
|
||||||
wakdo-migrate:
|
wakdo-migrate:
|
||||||
condition: service_completed_successfully
|
condition: service_completed_successfully
|
||||||
wakdo-db:
|
wakdo-db:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
|
||||||
# Healthcheck defini dans le Dockerfile (php -r exit 0).
|
|
||||||
|
|
||||||
# =======================================================================
|
|
||||||
# wakdo-web : Apache httpd (reverse FastCGI vers wakdo-app, expose via Traefik)
|
|
||||||
# =======================================================================
|
|
||||||
wakdo-web:
|
wakdo-web:
|
||||||
build:
|
build:
|
||||||
context: ./docker/apache
|
context: ./docker/apache
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
container_name: wakdo-web
|
container_name: wakdo-web
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
# Noms de domaine injectes dans les vhosts (ServerName ${TRAEFIK_DOMAIN_*}).
|
APP_HOST_KIOSK: ${APP_HOST_KIOSK}
|
||||||
TRAEFIK_DOMAIN_KIOSK: ${TRAEFIK_DOMAIN_KIOSK}
|
APP_HOST_ADMIN: ${APP_HOST_ADMIN}
|
||||||
TRAEFIK_DOMAIN_ADMIN: ${TRAEFIK_DOMAIN_ADMIN}
|
ports:
|
||||||
|
- "${HTTP_PORT:-8080}:80"
|
||||||
volumes:
|
volumes:
|
||||||
# Meme bind-mount que wakdo-app : Apache sert les fichiers statiques
|
|
||||||
# (HTML, CSS, JS, images) depuis ce dossier. PHP ne passe pas par
|
|
||||||
# ce chemin ici, il passe par le proxy FastCGI vers wakdo-app.
|
|
||||||
- ./src:/var/www/html
|
- ./src:/var/www/html
|
||||||
- wakdo_uploads:/var/www/html/public/uploads
|
- wakdo_uploads:/var/www/html/public/uploads
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
- wakdo_internal
|
- wakdo_internal
|
||||||
- reverse_proxy
|
|
||||||
|
|
||||||
depends_on:
|
depends_on:
|
||||||
wakdo-migrate:
|
wakdo-migrate:
|
||||||
condition: service_completed_successfully
|
condition: service_completed_successfully
|
||||||
|
|
@ -251,79 +124,26 @@ services:
|
||||||
wakdo-db:
|
wakdo-db:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
|
||||||
# === Labels Traefik : deux routers (kiosk + admin) sur le meme conteneur ===
|
|
||||||
# Le Traefik de l'hote decouvre ces labels automatiquement (provider docker).
|
|
||||||
# On ne configure PAS le certresolver ici : le Traefik hote le gere via
|
|
||||||
# sa propre config (acme.json, resolver par defaut).
|
|
||||||
labels:
|
|
||||||
- "traefik.enable=true"
|
|
||||||
- "traefik.docker.network=${REVERSE_PROXY_NETWORK}"
|
|
||||||
|
|
||||||
# --- Router kiosk (borne client) ---
|
|
||||||
- "traefik.http.routers.wakdo-kiosk.rule=Host(`${TRAEFIK_DOMAIN_KIOSK}`)"
|
|
||||||
- "traefik.http.routers.wakdo-kiosk.entrypoints=websecure"
|
|
||||||
- "traefik.http.routers.wakdo-kiosk.tls=true"
|
|
||||||
- "traefik.http.routers.wakdo-kiosk.tls.certresolver=letsencrypt"
|
|
||||||
- "traefik.http.routers.wakdo-kiosk.service=wakdo-kiosk-svc"
|
|
||||||
- "traefik.http.services.wakdo-kiosk-svc.loadbalancer.server.port=80"
|
|
||||||
|
|
||||||
# --- Router admin (back-office + API) ---
|
|
||||||
- "traefik.http.routers.wakdo-admin.rule=Host(`${TRAEFIK_DOMAIN_ADMIN}`)"
|
|
||||||
- "traefik.http.routers.wakdo-admin.entrypoints=websecure"
|
|
||||||
- "traefik.http.routers.wakdo-admin.tls=true"
|
|
||||||
- "traefik.http.routers.wakdo-admin.tls.certresolver=letsencrypt"
|
|
||||||
- "traefik.http.routers.wakdo-admin.service=wakdo-admin-svc"
|
|
||||||
- "traefik.http.services.wakdo-admin-svc.loadbalancer.server.port=80"
|
|
||||||
|
|
||||||
# --- Middleware : redirection HTTP -> HTTPS ---
|
|
||||||
# Applique aux 2 hosts via un router "catch-all" sur entrypoints=web.
|
|
||||||
- "traefik.http.routers.wakdo-kiosk-http.rule=Host(`${TRAEFIK_DOMAIN_KIOSK}`)"
|
|
||||||
- "traefik.http.routers.wakdo-kiosk-http.entrypoints=web"
|
|
||||||
- "traefik.http.routers.wakdo-kiosk-http.middlewares=wakdo-to-https"
|
|
||||||
- "traefik.http.routers.wakdo-admin-http.rule=Host(`${TRAEFIK_DOMAIN_ADMIN}`)"
|
|
||||||
- "traefik.http.routers.wakdo-admin-http.entrypoints=web"
|
|
||||||
- "traefik.http.routers.wakdo-admin-http.middlewares=wakdo-to-https"
|
|
||||||
- "traefik.http.middlewares.wakdo-to-https.redirectscheme.scheme=https"
|
|
||||||
- "traefik.http.middlewares.wakdo-to-https.redirectscheme.permanent=true"
|
|
||||||
|
|
||||||
# =======================================================================
|
|
||||||
# wakdo-cron : taches planifiees (backup, purge, agregations)
|
|
||||||
# =======================================================================
|
|
||||||
wakdo-cron:
|
wakdo-cron:
|
||||||
build:
|
build:
|
||||||
context: ./docker/cron
|
context: ./docker/cron
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
container_name: wakdo-cron
|
container_name: wakdo-cron
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
# init: true -> Docker injecte tini comme PID 1. dcron exige un init
|
|
||||||
# parent pour pouvoir setpgid() sur ses jobs (sinon "Operation not
|
|
||||||
# permitted" en boucle car un PID 1 sans init ne peut pas changer les
|
|
||||||
# groupes de processus). Cf. busybox-utils issue tracker.
|
|
||||||
init: true
|
init: true
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
# Credentials BDD pour mysqldump et les purges. Le user applicatif est en
|
|
||||||
# moindre privilege (DML + SELECT/SHOW VIEW/TRIGGER/LOCK TABLES, jamais le
|
|
||||||
# root password ; cf. db/init/10-scope-app-user.sh).
|
|
||||||
DB_HOST: ${DB_HOST}
|
DB_HOST: ${DB_HOST}
|
||||||
DB_PORT: ${DB_PORT}
|
DB_PORT: ${DB_PORT}
|
||||||
DB_NAME: ${DB_NAME}
|
DB_NAME: ${DB_NAME}
|
||||||
DB_USER: ${DB_USER}
|
DB_USER: ${DB_USER}
|
||||||
DB_PASSWORD: ${DB_PASSWORD}
|
DB_PASSWORD: ${DB_PASSWORD}
|
||||||
# Retention des donnees (mlt.md 13.4/13.5). Defaut applique par les scripts
|
|
||||||
# ET ici, pour rester coherent si la var manque du .env.
|
|
||||||
AUDIT_LOG_RETENTION_DAYS: ${AUDIT_LOG_RETENTION_DAYS:-365}
|
AUDIT_LOG_RETENTION_DAYS: ${AUDIT_LOG_RETENTION_DAYS:-365}
|
||||||
THROTTLE_PURGE_AFTER_HOURS: ${THROTTLE_PURGE_AFTER_HOURS:-24}
|
THROTTLE_PURGE_AFTER_HOURS: ${THROTTLE_PURGE_AFTER_HOURS:-24}
|
||||||
TZ: ${CRON_TIMEZONE:-Europe/Paris}
|
TZ: ${CRON_TIMEZONE:-Europe/Paris}
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
# Bind-mount vers l'hote pour les dumps : inspectables par ls, scp-able
|
|
||||||
# hors docker. Le dossier ./var/backups est gitignore.
|
|
||||||
- ./var/backups:/backups
|
- ./var/backups:/backups
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
- wakdo_internal
|
- wakdo_internal
|
||||||
|
|
||||||
depends_on:
|
depends_on:
|
||||||
wakdo-db:
|
wakdo-db:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@
|
||||||
# Wakdo - vhosts applicatifs
|
# Wakdo - vhosts applicatifs
|
||||||
#
|
#
|
||||||
# Un seul conteneur Apache derriere Traefik sert **les deux** FQDN :
|
# Un seul conteneur Apache derriere Traefik sert **les deux** FQDN :
|
||||||
# - TRAEFIK_DOMAIN_KIOSK -> /var/www/html/public/borne (borne client, Bloc 1)
|
# - APP_HOST_KIOSK -> /var/www/html/public/borne (borne client, Bloc 1)
|
||||||
# - TRAEFIK_DOMAIN_ADMIN -> /var/www/html/public/admin (back-office + API, Bloc 2)
|
# - APP_HOST_ADMIN -> /var/www/html/public/admin (back-office + API, Bloc 2)
|
||||||
#
|
#
|
||||||
# Comme Traefik termine TLS en amont et communique en HTTP clair avec Apache
|
# Comme Traefik termine TLS en amont et communique en HTTP clair avec Apache
|
||||||
# sur le reseau docker, les vhosts ecoutent sur :80 et font confiance aux
|
# sur le reseau docker, les vhosts ecoutent sur :80 et font confiance aux
|
||||||
|
|
@ -39,8 +39,8 @@
|
||||||
|
|
||||||
# === Borne client (Bloc 1 - front vanilla HTML/CSS/JS) ===
|
# === Borne client (Bloc 1 - front vanilla HTML/CSS/JS) ===
|
||||||
<VirtualHost *:80>
|
<VirtualHost *:80>
|
||||||
# Hostname injecte par la var d'env TRAEFIK_DOMAIN_KIOSK au runtime.
|
# Hostname injecte par la var d'env APP_HOST_KIOSK au runtime.
|
||||||
ServerName ${TRAEFIK_DOMAIN_KIOSK}
|
ServerName ${APP_HOST_KIOSK}
|
||||||
|
|
||||||
DocumentRoot "/var/www/html/public/borne"
|
DocumentRoot "/var/www/html/public/borne"
|
||||||
|
|
||||||
|
|
@ -89,7 +89,7 @@
|
||||||
|
|
||||||
# === Back-office + API REST (Bloc 2 - PHP from scratch + MVC) ===
|
# === Back-office + API REST (Bloc 2 - PHP from scratch + MVC) ===
|
||||||
<VirtualHost *:80>
|
<VirtualHost *:80>
|
||||||
ServerName ${TRAEFIK_DOMAIN_ADMIN}
|
ServerName ${APP_HOST_ADMIN}
|
||||||
|
|
||||||
DocumentRoot "/var/www/html/public/admin"
|
DocumentRoot "/var/www/html/public/admin"
|
||||||
|
|
||||||
|
|
@ -128,7 +128,7 @@
|
||||||
</DirectoryMatch>
|
</DirectoryMatch>
|
||||||
|
|
||||||
# CORS : l'API admin sous /api/* doit accepter les requetes venant
|
# CORS : l'API admin sous /api/* doit accepter les requetes venant
|
||||||
# de la borne kiosk (TRAEFIK_DOMAIN_KIOSK). Wildcard interdit.
|
# de la borne kiosk (APP_HOST_KIOSK). Wildcard interdit.
|
||||||
# La vraie valeur vient de CORS_ALLOWED_ORIGIN dans .env, lue cote PHP.
|
# La vraie valeur vient de CORS_ALLOWED_ORIGIN dans .env, lue cote PHP.
|
||||||
# Ici on pose juste les headers de prealable OPTIONS.
|
# Ici on pose juste les headers de prealable OPTIONS.
|
||||||
<Location /api>
|
<Location /api>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue