--- 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 @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= ALPID_CLIENT_ID= ALPID_CLIENT_SECRET= ALPID_DISCOVERY_URL=https://alpid.alpinux.org/realms/alpinux/.well-known/openid-configuration DATABASE= ``` ```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 sudo mkdir -p sudo chown : ``` ### 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 @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//` | Public (page intro) | | `/quiz//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 ```