Déploiement de dynamic.alpinux.org¶
Application Flask de quiz interactifs, partiellement publique et partiellement réservée aux membres AlpID.
Pour qui ?
Procédure pour les mainteneurs avec accès SSH au serveur.
Architecture¶
Navigateur
│ HTTPS
▼
Apache (reverse proxy, SSL)
│ HTTP 127.0.0.1:5001
▼
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¶
ssh alpinux@alpinux.org
git clone https://gitea.alpinux.org/alpinux.cedrica5l/alpinux.site.2026.git \
/home/alpinux/site
2. Créer l'environnement Python¶
cd /home/alpinux/site/dynamic
python3 -m venv venv
venv/bin/pip install -r requirements.txt gunicorn
3. Configurer les variables d'environnement¶
sudo mkdir /etc/dynamic-alpinux
sudo cp /home/alpinux/site/dynamic/.env.example /etc/dynamic-alpinux/config.env
sudo nano /etc/dynamic-alpinux/config.env
Remplissez les valeurs :
SECRET_KEY=<générer avec : python3 -c "import secrets; print(secrets.token_hex(32))">
ALPID_CLIENT_ID=dynamic-alpinux
ALPID_CLIENT_SECRET=<obtenir depuis la console Keycloak AlpID>
ALPID_DISCOVERY_URL=https://alpid.alpinux.org/realms/alpinux/.well-known/openid-configuration
DATABASE=/var/lib/dynamic-alpinux/scores.db
4. Créer les répertoires de données et de logs¶
sudo mkdir -p /var/lib/dynamic-alpinux
sudo mkdir -p /var/log/dynamic-alpinux
sudo chown alpinux:alpinux /var/lib/dynamic-alpinux /var/log/dynamic-alpinux
5. Configurer AlpID (Keycloak)¶
Dans la console d'administration Keycloak (https://alpid.alpinux.org) :
- Clients → Créer un client
- Client ID :
dynamic-alpinux - Client authentication : activé (pour obtenir un
client_secret) - Valid redirect URIs :
https://dynamic.alpinux.org/auth/callback - Web origins :
https://dynamic.alpinux.org - Notez le Client secret dans l'onglet Credentials
6. Installer le service systemd¶
sudo cp /home/alpinux/site/scripts/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¶
# Activer les modules nécessaires
sudo a2enmod proxy proxy_http headers ssl
# Copier le vhost
sudo cp /home/alpinux/site/scripts/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¶
Mise à jour¶
ssh alpinux@alpinux.org
cd /home/alpinux/site
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 |
| Logs accès | tail -f /var/log/dynamic-alpinux/access.log |
| Logs erreurs | tail -f /var/log/dynamic-alpinux/error.log |
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 :
{
"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=Expertanswer: index 0-based de la bonne réponse danschoicesmembers_only:truepour restreindre aux membres AlpID
Après modification, redémarrez le service pour recharger le JSON :