# # Wakdo - vhosts applicatifs # # Un seul conteneur Apache derriere Traefik sert **les deux** FQDN : # - APP_HOST_KIOSK -> /var/www/html/public/borne (borne client, Bloc 1) # - 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 # sur le reseau docker, les vhosts ecoutent sur :80 et font confiance aux # headers X-Forwarded-* fournis par Traefik. # # Le SetHandler "proxy:fcgi://wakdo-app:9000" est le coeur du reverse FastCGI : # toute requete *.php est relayee au pool PHP-FPM via TCP sur le reseau interne # wakdo_internal. wakdo-app n'est JAMAIS joignable directement depuis l'exterieur. # # === Healthcheck interne Docker (non expose publiquement) === # Listen sans ServerName = catch-all. Utilise par le HEALTHCHECK du Dockerfile. # Sert un fichier statique healthz.txt (body = "OK\n") au lieu d'un # RewriteRule [R=200] qui declenchait le template ErrorDocument generique # et faisait apparaitre la mention "internal error" dans le body d'un 200. # Le fichier vit dans /usr/local/apache2/htdocs/ (chemin Apache natif, jamais # bind-monte) et non dans /var/www/html/ qui est ecrase par le bind-mount # ./src au runtime. DocumentRoot "/usr/local/apache2/htdocs" Alias /healthz /usr/local/apache2/htdocs/healthz.txt Require all granted # Pas de cache : la sonde doit toujours toucher Apache. Header set Cache-Control "no-store" # === Borne client (Bloc 1 - front vanilla HTML/CSS/JS) === # Hostname injecte par la var d'env APP_HOST_KIOSK au runtime. ServerName ${APP_HOST_KIOSK} DocumentRoot "/var/www/html/public/borne" # Confiance aux headers X-Forwarded-* de Traefik. # mod_remoteip pourrait etre active pour restaurer la vraie IP client # dans les logs, mais en l'etat le header X-Forwarded-For est loggue # dans combined, ce qui suffit pour un projet RNCP. Options -Indexes +FollowSymLinks AllowOverride None Require all granted # SPA-like fallback : toute URL non-fichier -> index.html # (pour permettre de bookmarker un chemin profond dans la borne). RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^ index.html [L] # Securite supplementaire : expose uniquement public/borne, pas la racine. Require all denied # Compression text/html, css, js, json (Cr 1.e.8 temps de chargement). AddOutputFilterByType DEFLATE text/html text/css text/javascript \ application/javascript application/json image/svg+xml # Cache long sur les assets versionnes (futur : hash dans le nom de fichier). Header set Cache-Control "public, max-age=604800" # Borne : pas de code PHP execute cote kiosk (Bloc 1 = front only). # Si une requete *.php arrive ici, on la refuse pour forcer l'isolation. Require all denied ErrorLog /proc/self/fd/2 CustomLog /proc/self/fd/1 combined # === Back-office + API REST (Bloc 2 - PHP from scratch + MVC) === ServerName ${APP_HOST_ADMIN} DocumentRoot "/var/www/html/public/admin" Options -Indexes +FollowSymLinks AllowOverride None Require all granted # DirectoryIndex etend a index.php pour que la racine `/` serve # le front controller PHP sans passer par RewriteRule (qui ne se # declenche pas sur un repertoire existant a cause du `!-d`). DirectoryIndex index.php index.html # Front controller MVC : toute requete non-fichier passe par index.php # qui dispatche via le Router (src/Core/Router.php a venir en P2). RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^ index.php [L] # Reverse FastCGI : toute requete *.php est executee par wakdo-app:9000. # Format proxy:fcgi://: # SetHandler s'applique au chemin courant du . SetHandler "proxy:fcgi://wakdo-app:9000" # Protection des fichiers sensibles du projet si jamais un chemin se # retrouve sous DocumentRoot par erreur (.env, .git, config/). Require all denied Require all denied # CORS : l'API admin sous /api/* doit accepter les requetes venant # de la borne kiosk (APP_HOST_KIOSK). Wildcard interdit. # La vraie valeur vient de CORS_ALLOWED_ORIGIN dans .env, lue cote PHP. # Ici on pose juste les headers de prealable OPTIONS. # Les headers definitifs sont poses par le middleware PHP. # Apache ne fait que relayer le preflight sans le casser. Header set X-Wakdo-Handled-By "apache-vhost" # Compression back-office (HTML admin + JSON API) AddOutputFilterByType DEFLATE text/html text/css text/javascript \ application/javascript application/json # Securite : cookies httpOnly + secure sont forces cote PHP (voir php.ini). # Ici on ajoute un header CSP minimal : l'admin n'a pas besoin de charger # de resources externes pour un MVP (pas de CDN, pas d'analytics). Header always set Content-Security-Policy "default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; script-src 'self'" Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains" ErrorLog /proc/self/fd/2 CustomLog /proc/self/fd/1 combined