Les vars de retention (AUDIT_LOG_RETENTION_DAYS, THROTTLE_PURGE_AFTER_HOURS)
etaient documentees comme purges cron mais aucun script/job n'existait, et les
vars n'etaient pas injectees au conteneur wakdo-cron (faux-semblant de conformite).
- purge-audit-log.sh : DELETE audit_log au-dela de AUDIT_LOG_RETENTION_DAYS
(defaut 365). Unique exception documentee a l'append-only (RG-T14) : purge de
retention planifiee, pas une mutation applicative.
- purge-throttle.sh : DELETE login_throttle + pin_throttle sans verrou actif et
plus vieux que THROTTLE_PURGE_AFTER_HOURS (defaut 24), predicat mlt.md 13.5.
- crontab : jobs actives (15 4 audit, 45 4 throttle), fenetre de maintenance.
- docker-compose.yml : injection des 2 vars (avec defaut) au conteneur cron ;
commentaire env aligne sur le user en moindre privilege.
Hors scope : la purge de customer_order (ORDER_RETENTION_DAYS) reste differee
tant que le domaine commande n'existe pas (RGPD = anonymisation a definir avec
le domaine, pas un simple DELETE).
Verifie : scripts lances dans l'image cron rebuildee contre la base dev (user
scope) -> exit 0 ; test positif/negatif sur login_throttle : la ligne stale sans
verrou est purgee, la ligne a verrou actif est conservee.
Three changes bundled because the stubs surfaced two pre-existing infra bugs
that had never been hit (the smoke test only exercised PHP via 'docker exec',
not via the full Apache->PHP-FPM FastCGI path).
- src/public/borne/index.html : minimal HTML stub for the kiosk vhost
(200 OK with the imported logo)
- src/public/admin/index.php : minimal PHP stub that proves the full
FastCGI chain works end-to-end (renders PHP_VERSION + current timestamp)
- docker/apache/vhost.conf : add 'DirectoryIndex index.php index.html' on
the admin vhost. Without it, hitting / returned 403 because the default
Apache DirectoryIndex is index.html only, and the existing RewriteRule
did not apply to the directory request (\!-d cond was false).
- docker/php-fpm/www.conf : comment out 'listen.allowed_clients = any'.
PHP-FPM 8.3 rejects 'any' with 'Wrong IP address' and ends up dropping
every connection from Apache. With the directive absent, all connections
are accepted, which is acceptable in our isolated Docker network.
Three issues surfaced when running 'make init' on the deployment host
and were fixed in place:
- wakdo_internal network: explicit subnet 192.168.148.0/24 (RFC 1918,
in the free 192.168.144-159 gap). The host's Docker daemon has its
default address pools saturated by other stacks, so auto-allocation
failed. An explicit subnet bypasses the allocator and isolates Wakdo
from neighbour churn.
- wakdo-cron: init: true added so Docker injects tini as PID 1. Without
it, dcron loops on 'setpgid: Operation not permitted' because PID 1
in a container without an init system cannot change process groups
for its children.
- healthz vhost: served as a static file from /usr/local/apache2/htdocs/
instead of a RewriteRule [R=200] that triggered Apache's ErrorDocument
template (and leaked 'internal error' wording into a 200 response).
The file lives outside /var/www/html/ which is bind-mounted at runtime
and would otherwise mask the COPY.
Deliver the full Docker stack for Bloc 5 DevOps (Cr 7.c.3 and 7.c.4):
- docker/apache/ Custom httpd:2.4-alpine with hardened main config,
MPM event tuning and 3 vhosts (healthz, kiosk static,
admin reverse FCGI to wakdo-app:9000). Kiosk vhost
explicitly denies .php to enforce Bloc 1 isolation.
- docker/php-fpm/ Custom php:8.3-fpm-alpine3.20 with pdo_mysql, opcache,
intl, exif, zip and tini for signal handling.
Dynamic pool 3-10 workers listening on TCP 9000.
- docker/cron/ Custom alpine:3.20 with dcron, mariadb-client, gzip.
Nightly mysqldump at 03h00 with 14-day rotation and
512-byte sanity check. Purge and stats jobs templated.
- docker-compose.yml 4 services orchestrated on 2 networks (internal
bridge + external reverse-proxy). 2 named volumes
for DB and uploads, bind-mount for backups.
Traefik labels for 2 routers with HTTPS redirect.
Makefile adds `make backup` (manual dump) and `make backup-ls`.
.gitignore adds /var/ for backup bind-mount path.
docs/journal/2026-04-24--infra-docker.md documents 5 decisions with
alternatives, maps 16 RNCP criteria to artefacts and prepares 6 jury Q&A.
Validated: `docker compose config --quiet` passes. Smoke test deferred
to next session (requires server .env).