# DEPLOY — Le Donut Infolab Procédure exacte de déploiement sur le serveur **Donut Marseille**. - Hôte : `arnaud.donut@82.66.40.209` - OS : Ubuntu 26.04 - Sous-domaine : `infolab.ledonut-marseille.org` - Conteneur PHP : `donut-infolab` (UID `33` = www-data côté Apache) - BDD : conteneur existant `donut-mariadb`, réseau Docker `donut-net` - Reverse proxy : Caddy natif sur l'hôte - Front : SPA Vue 3 buildé (statique) servi par Caddy depuis `/srv/donut/web/infolab-front/dist/` > ⚠️ Pré-requis DNS : créer chez OVH un record `A infolab.ledonut-marseille.org → 82.66.40.209` > **avant** le reload Caddy (sinon échec ACME challenge). --- ## 0. Pré-requis vérifiés une fois ```bash ssh arnaud.donut@82.66.40.209 # Le réseau donut-net existe docker network ls | grep donut-net # Le mariadb tourne et est joignable depuis donut-net docker ps | grep donut-mariadb # /srv/donut/secrets/mariadb.env est en place et lisible par root sudo ls -l /srv/donut/secrets/mariadb.env # Le group donut-admins existe getent group donut-admins ``` --- ## 1. Copier le backend vers le serveur Depuis ta machine de dev (à la racine du repo) : ```bash # Code app PHP -> /srv/donut/web/infolab/ (bind-mount dans le conteneur, UID 33) rsync -avz --delete \ --exclude '.git' --exclude '.idea' --exclude '.env' --exclude 'tests' \ --exclude 'docker-compose.yml' --exclude 'Dockerfile' --exclude 'caddy.conf' \ --exclude 'migrations' --exclude 'DEPLOY.md' --exclude 'INSTRUCTIONS.md' \ --exclude 'frontend' --exclude 'docs' \ ./ arnaud.donut@82.66.40.209:/tmp/infolab-app/ # Fichiers d'orchestration -> /srv/donut/compose/infolab/ rsync -avz \ docker-compose.yml Dockerfile caddy.conf README.md DEPLOY.md .env.example \ migrations \ arnaud.donut@82.66.40.209:/tmp/infolab-compose/ ``` Puis sur le serveur : ```bash ssh arnaud.donut@82.66.40.209 # Code app (UID 33 = www-data du conteneur Apache) sudo mkdir -p /srv/donut/web/infolab sudo rsync -a --delete /tmp/infolab-app/ /srv/donut/web/infolab/ sudo chown -R 33:33 /srv/donut/web/infolab sudo find /srv/donut/web/infolab -type d -exec chmod 755 {} \; sudo find /srv/donut/web/infolab -type f -exec chmod 644 {} \; # Orchestration (root:donut-admins, lisible par les admins) sudo mkdir -p /srv/donut/compose/infolab sudo rsync -a /tmp/infolab-compose/ /srv/donut/compose/infolab/ sudo chown -R root:donut-admins /srv/donut/compose/infolab sudo chmod 750 /srv/donut/compose/infolab sudo chmod 640 /srv/donut/compose/infolab/* # Cleanup tmp rm -rf /tmp/infolab-app /tmp/infolab-compose ``` --- ## 1bis. Builder & copier le frontend (SPA Vue) Le SPA est compilé localement (Node 22+ requis) et déployé en statique. Pas de Node sur le serveur prod. ```bash # Sur la machine de dev, à la racine du repo cd frontend npm ci # ou `npm install` la 1re fois npm run build # produit frontend/dist/ ls -la dist/ # index.html + assets/ avec hash # Copie de l'artifact vers le serveur (rsync direct, fichiers statiques) rsync -avz --delete dist/ arnaud.donut@82.66.40.209:/tmp/infolab-front-dist/ cd .. ``` Sur le serveur : ```bash ssh arnaud.donut@82.66.40.209 sudo mkdir -p /srv/donut/web/infolab-front/dist sudo rsync -a --delete /tmp/infolab-front-dist/ /srv/donut/web/infolab-front/dist/ # Caddy tourne en `caddy` user — donner l'accès en lecture est suffisant sudo chown -R caddy:caddy /srv/donut/web/infolab-front sudo find /srv/donut/web/infolab-front -type d -exec chmod 755 {} \; sudo find /srv/donut/web/infolab-front -type f -exec chmod 644 {} \; rm -rf /tmp/infolab-front-dist ``` > ⚠️ Le build embarque l'URL de l'API en relatif (`/api/...`) — donc le SPA et l'API > **doivent** être servis depuis le même domaine (ce que fait notre `caddy.conf`). --- ## 2. Créer les secrets `/srv/donut/secrets/infolab.env` ```bash ssh arnaud.donut@82.66.40.209 DB_PASS="$(openssl rand -hex 24)" ADMIN_TOKEN="$(openssl rand -hex 32)" sudo tee /srv/donut/secrets/infolab.env > /dev/null < reverse_proxy vers le conteneur PHP `127.0.0.1:8003` - tout le reste -> sert `/srv/donut/web/infolab-front/dist/` (SPA), fallback `index.html` ```bash grep -n 'infolab' /etc/caddy/Caddyfile # Si manquant, ajouter en fin de Caddyfile : echo 'import /srv/donut/compose/infolab/caddy.conf' | sudo tee -a /etc/caddy/Caddyfile # Valider la syntaxe puis recharger sudo caddy validate --config /etc/caddy/Caddyfile sudo systemctl reload caddy ``` Caddy va négocier le certificat Let's Encrypt (à condition que le DNS A record soit en place — voir avertissement en tête de fichier). Vérifier qu'il sert bien le SPA et l'API : ```bash curl -sI https://infolab.ledonut-marseille.org/ # SPA -> 200 text/html curl -sI https://infolab.ledonut-marseille.org/api/health # API -> 200 application/json curl -sI https://infolab.ledonut-marseille.org/whatever-fake # SPA fallback -> 200 index.html ``` --- ## 6. Vérification finale ```bash # Depuis la machine de dev (TLS terminé par Caddy) curl -s https://infolab.ledonut-marseille.org/api/health curl -s https://infolab.ledonut-marseille.org/api/categories | head -c 400 # Smoke tests complets (lit ADMIN_TOKEN depuis le secret côté serveur) ssh arnaud.donut@82.66.40.209 'sudo bash -c " TOKEN=\$(grep ^ADMIN_TOKEN= /srv/donut/secrets/infolab.env | cut -d= -f2-) INFOLAB_URL=https://infolab.ledonut-marseille.org ADMIN_TOKEN=\$TOKEN \ /srv/donut/compose/infolab/tests/smoke.sh "' ``` Si tout est vert : `OK : 11 / FAIL : 0`. --- ## 7. Cycle de mise à jour (pour plus tard) ```bash # Backend PHP rsync -avz --delete --exclude '.git' --exclude '.env' \ public/ src/ arnaud.donut@82.66.40.209:/srv/donut/web/infolab/ # Frontend Vue (build à chaque release) (cd frontend && npm ci && npm run build) rsync -avz --delete frontend/dist/ \ arnaud.donut@82.66.40.209:/srv/donut/web/infolab-front/dist/ # Si changement Dockerfile / docker-compose / migrations : rsync -avz docker-compose.yml Dockerfile migrations/ \ arnaud.donut@82.66.40.209:/srv/donut/compose/infolab/ ssh arnaud.donut@82.66.40.209 << 'EOF' sudo /srv/donut/compose/infolab/migrations/apply.sh # nouvelle migration éventuelle cd /srv/donut/compose/infolab sudo docker compose --env-file /srv/donut/secrets/infolab.env up -d --build sudo chown -R 33:33 /srv/donut/web/infolab sudo chown -R caddy:caddy /srv/donut/web/infolab-front EOF ``` --- ## Points à valider une fois en prod - [ ] DNS `A infolab.ledonut-marseille.org → 82.66.40.209` ajouté chez OVH - [ ] Certificat Let's Encrypt négocié OK (`caddy.log` côté hôte) - [ ] `ADMIN_TOKEN` archivé dans le gestionnaire de mots de passe partagé - [ ] `tests/smoke.sh` vert depuis l'extérieur - [ ] SPA accessible : `https://infolab.ledonut-marseille.org/` renvoie la page d'accueil - [ ] SPA routing OK : `https://infolab.ledonut-marseille.org/projects` aussi (pas de 404 — fallback Caddy) - [ ] Conteneur `donut-infolab` visible dans Dozzle (logs Apache + PHP via stderr) - [ ] Pas de fuite : `curl -I https://infolab.ledonut-marseille.org/.env` → 403/404