alpinux-wiki/docs/technique/deploiement-dynamic.md

232 lines
5.7 KiB
Markdown

---
description: Déploiement de dynamic.alpinux.org — app Flask, Gunicorn, Apache reverse proxy, AlpID OIDC.
---
# Déploiement de dynamic.alpinux.org
Application Flask de quiz interactifs, partiellement publique et partiellement réservée aux membres AlpID.
!!! note "Pour qui ?"
Procédure pour les mainteneurs avec accès SSH au serveur.
---
## Architecture
```
Navigateur
│ HTTPS
Apache (reverse proxy, SSL)
│ HTTP (port local dédié)
Gunicorn (2 workers)
Flask app (dynamic/)
│ │
▼ ▼
SQLite AlpID OIDC
(scores.db) (alpid.alpinux.org)
```
---
## Installation (première fois)
### 1. Cloner le dépôt sur le serveur
```bash
ssh <user>@alpinux.org
git clone https://gitea.alpinux.org/alpinux.cedrica5l/alpinux.site.2026.git \
$APP_DIR
```
### 2. Créer l'environnement Python
```bash
cd $APP_DIR/dynamic
python3 -m venv venv
venv/bin/pip install -r requirements.txt gunicorn
```
### 3. Configurer les variables d'environnement
```bash
sudo mkdir /etc/dynamic-alpinux
sudo cp $APP_DIR/dynamic/.env.example /etc/dynamic-alpinux/config.env
sudo nano /etc/dynamic-alpinux/config.env
```
Remplissez les valeurs :
```bash
SECRET_KEY=<générer avec : python3 -c "import secrets; print(secrets.token_hex(32))">
ALPID_CLIENT_ID=<client-id-configuré-dans-keycloak>
ALPID_CLIENT_SECRET=<obtenir depuis la console Keycloak AlpID>
ALPID_DISCOVERY_URL=https://alpid.alpinux.org/realms/alpinux/.well-known/openid-configuration
DATABASE=<chemin vers le fichier scores.db>
```
```bash
sudo chmod 600 /etc/dynamic-alpinux/config.env
```
### 4. Créer les répertoires de données et de logs
```bash
sudo mkdir -p <répertoire données>
sudo mkdir -p <répertoire logs>
sudo chown <user>:<group> <répertoire données> <répertoire logs>
```
### 5. Configurer AlpID (Keycloak)
Dans la console d'administration Keycloak (`https://alpid.alpinux.org`) :
1. **Clients****Créer un client**
2. **Client ID** : le client ID choisi pour cette app
3. **Client authentication** : activé (pour obtenir un `client_secret`)
4. **Valid redirect URIs** : `https://dynamic.alpinux.org/auth/callback`
5. **Web origins** : `https://dynamic.alpinux.org`
6. Notez le **Client secret** dans l'onglet *Credentials*
### 6. Installer le service systemd
Les fichiers de configuration systemd et Apache sont conservés **hors dépôt** (`infra/` local).
```bash
sudo cp infra/dynamic/dynamic.alpinux.org.service \
/etc/systemd/system/dynamic-alpinux.service
sudo systemctl daemon-reload
sudo systemctl enable --now dynamic-alpinux
sudo systemctl status dynamic-alpinux
```
### 7. Configurer Apache
```bash
sudo a2enmod proxy proxy_http headers ssl
sudo cp infra/dynamic/dynamic.alpinux.org.vhost.conf \
/etc/apache2/sites-available/dynamic.alpinux.org.conf
sudo a2ensite dynamic.alpinux.org
sudo apachectl configtest
sudo systemctl reload apache2
```
### 8. Obtenir le certificat SSL
```bash
sudo certbot --apache -d dynamic.alpinux.org
```
---
## Mise à jour
```bash
ssh <user>@alpinux.org
cd $APP_DIR
git pull
cd dynamic
venv/bin/pip install -r requirements.txt # si requirements.txt a changé
sudo systemctl restart dynamic-alpinux
```
---
## Gestion du service
| Action | Commande |
|---|---|
| Démarrer | `sudo systemctl start dynamic-alpinux` |
| Arrêter | `sudo systemctl stop dynamic-alpinux` |
| Redémarrer | `sudo systemctl restart dynamic-alpinux` |
| État | `sudo systemctl status dynamic-alpinux` |
| Logs en direct | `sudo journalctl -u dynamic-alpinux -f` |
---
## Structure de l'application
```
dynamic/
├── app.py ← point d'entrée Flask
├── auth_utils.py ← décorateur @login_required
├── db.py ← SQLite (scores)
├── quiz.py ← chargement du JSON
├── requirements.txt
├── .env.example
├── data/
│ └── quizzes.json ← toutes les questions (source de vérité)
├── routes/
│ ├── public.py ← accueil, liste, jeu, résultat
│ ├── auth.py ← /auth/login, /auth/callback, /auth/logout
│ └── protected.py ← /profil/
├── static/
│ ├── style.css
│ └── quiz.js
└── templates/
├── base.html
├── index.html
├── quiz/
│ ├── intro.html
│ ├── play.html
│ └── result.html
└── profil/
└── index.html
```
---
## Accès public vs membres
| URL | Accès |
|---|---|
| `/` | Public |
| `/quiz/` | Public (aperçu de tous les quiz) |
| `/quiz/<id>/` | Public (page intro) |
| `/quiz/<id>/jouer` | Public si `members_only: false`, sinon AlpID requis |
| `/profil/` | AlpID requis |
| `/auth/login` | Redirect → AlpID |
| `/auth/callback` | Retour OIDC (interne) |
Les quiz avancés (niveau 4) et experts (niveau 5) ont `"members_only": true` dans `data/quizzes.json`.
---
## Ajouter un quiz
Éditez `dynamic/data/quizzes.json` et ajoutez un objet au tableau :
```json
{
"id": "mon-quiz",
"title": "Titre du quiz",
"description": "Description courte.",
"level": "Intermédiaire",
"level_id": 3,
"members_only": false,
"duration_min": 5,
"icon": "🐧",
"questions": [
{
"id": 1,
"text": "Question ?",
"choices": ["Réponse A", "Réponse B", "Réponse C", "Réponse D"],
"answer": 0
}
]
}
```
- `level_id` : 1=Découverte, 2=Débutant, 3=Intermédiaire, 4=Avancé, 5=Expert
- `answer` : index 0-based de la bonne réponse dans `choices`
- `members_only` : `true` pour restreindre aux membres AlpID
Après modification, redémarrez le service pour recharger le JSON :
```bash
sudo systemctl restart dynamic-alpinux
```