Reprendre la documentation de déploiement, qui vivait dans alpinux-owni
Ce dépôt d'infrastructure décrit la machine ; le déploiement de ce site-ci le regarde lui, et le tenir ailleurs garantissait qu'il divergerait du code qu'il décrit. Repris tel quel depuis alpinux-owni/docs/, où il est supprimé en retour. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SFbwnJurBwTs7x7t93ecku
This commit is contained in:
parent
8655c250ec
commit
ab0cc146ea
1 changed files with 156 additions and 0 deletions
156
INFRASTRUCTURE.md
Normal file
156
INFRASTRUCTURE.md
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
# static.alpinux.org — infrastructure
|
||||
|
||||
Configuration de référence pour `static.alpinux.org` (CDN assets Alpinux + tableau de bord).
|
||||
|
||||
## Fichiers
|
||||
|
||||
| Fichier | Description |
|
||||
|---------|-------------|
|
||||
| `static.alpinux.org.vhost.conf` | Configuration Apache — **référence audit, non déployé manuellement** |
|
||||
| `static-cdn.service` | Systemd unit pour l'app Flask (tableau de bord) |
|
||||
|
||||
## Gestion via ISPConfig
|
||||
|
||||
Le VirtualHost est **créé et géré par ISPConfig** (`https://owni.alpinux.org:8080`).
|
||||
|
||||
Pour recréer ou reconfigurer le site :
|
||||
1. *Sites → Ajouter un site web* — domaine `static.alpinux.org`
|
||||
2. Onglet *SSL* → activer **Let's Encrypt**
|
||||
3. PHP désactivé (onglet Options avancées)
|
||||
|
||||
## Tableau de bord Flask (app/)
|
||||
|
||||
L'app Flask (`static/app/`) sert la page d'accueil de `static.alpinux.org` après authentification AlpID.
|
||||
|
||||
### Déploiement
|
||||
|
||||
Depuis le poste de développement :
|
||||
|
||||
```bash
|
||||
cd org.alpinux.owni/static
|
||||
scripts/deploy-app.sh
|
||||
```
|
||||
|
||||
Le script :
|
||||
- rsync `app/` → `/opt/static-cdn/` sur le serveur (hors web root)
|
||||
- crée le venv Python et installe les dépendances
|
||||
- installe et démarre `static-cdn.service` via systemd
|
||||
|
||||
Créer le fichier `/opt/static-cdn/.env` sur le serveur après le premier déploiement :
|
||||
|
||||
```bash
|
||||
ssh alpinux.org
|
||||
nano /opt/static-cdn/.env
|
||||
sudo systemctl restart static-cdn
|
||||
```
|
||||
|
||||
### Apache — directives proxy
|
||||
|
||||
Ajouter dans ISPConfig → Sites → `static.alpinux.org` → onglet **Options** → champ
|
||||
**Directives Apache personnalisées SSL** :
|
||||
|
||||
```apache
|
||||
# Fichiers CDN publics — Apache sert directement depuis DocumentRoot
|
||||
ProxyPass /logo/ !
|
||||
ProxyPass /wiki/ !
|
||||
ProxyPass /error/ !
|
||||
ProxyPass /favicon.ico !
|
||||
ProxyPass /robots.txt !
|
||||
|
||||
# Tableau de bord → Flask sur 127.0.0.1:5003
|
||||
RequestHeader set X-Forwarded-Proto "https"
|
||||
ProxyPreserveHost On
|
||||
ProxyPass / http://127.0.0.1:5003/
|
||||
ProxyPassReverse / http://127.0.0.1:5003/
|
||||
```
|
||||
|
||||
Note : `/stats/` n'est **pas** exclu — il est servi par Flask avec authentification AlpID.
|
||||
|
||||
`RequestHeader set X-Forwarded-Proto "https"` est indispensable : sans lui, Flask génère
|
||||
le `redirect_uri` en HTTP et Keycloak refuse le callback.
|
||||
|
||||
### Variables d'environnement (`/opt/static-cdn/.env`)
|
||||
|
||||
| Variable | Obligatoire | Valeur / Description |
|
||||
|----------|-------------|----------------------|
|
||||
| `SECRET_KEY` | oui | Chaîne aléatoire longue (`python3 -c "import secrets; print(secrets.token_hex(32))"`) |
|
||||
| `ALPID_CLIENT_ID` | oui | `static-cdn` (client créé dans Keycloak) |
|
||||
| `ALPID_CLIENT_SECRET` | oui | Secret généré par Keycloak |
|
||||
| `ALPID_DISCOVERY_URL` | oui | `https://alpid.alpinux.org/realms/master/.well-known/openid-configuration` |
|
||||
| `ADMIN_GROUPS` | non | Groupes Keycloak autorisés (défaut : `admins`) — nécessite le claim `groups` activé côté Keycloak |
|
||||
| `ADMIN_EMAILS` | non | Emails autorisés séparés par virgule — fallback si `groups` n'est pas dans le token |
|
||||
| `ASSETS_ROOT` | oui | `/var/www/clients/client1/web17/web` |
|
||||
| `STATS_FILE` | non | `/opt/static-cdn/goaccess.html` — rapport HTML GoAccess |
|
||||
| `STATS_JSON` | non | `/opt/static-cdn/goaccess.json` — statistiques par fichier (badges "vues" dans browse) |
|
||||
|
||||
### Keycloak — realm et client
|
||||
|
||||
- **Realm** : `master` (seul realm actif sur cette instance AlpID)
|
||||
- **Client ID** : `static-cdn`
|
||||
- **Redirect URI** : `https://static.alpinux.org/auth/callback`
|
||||
- **Scopes demandés** : `openid profile email` — le scope `groups` n'est **pas** activé
|
||||
sur ce client ; l'autorisation se fait via `ADMIN_EMAILS` ou, si les deux sont absents,
|
||||
tous les utilisateurs AlpID sont acceptés
|
||||
|
||||
### Logique d'autorisation (priorité décroissante)
|
||||
|
||||
1. Claim `groups` présent dans le token → vérification contre `ADMIN_GROUPS`
|
||||
2. `ADMIN_EMAILS` défini dans `.env` → l'email du compte doit figurer dans la liste
|
||||
3. Ni l'un ni l'autre → tout utilisateur authentifié via AlpID est accepté
|
||||
|
||||
Pour restreindre à un seul administrateur :
|
||||
```
|
||||
ADMIN_EMAILS=cedric.alpinux@acemail.fr
|
||||
```
|
||||
|
||||
## Chemin web root
|
||||
|
||||
ISPConfig attribue `/var/www/clients/client1/web17/web` au site `static.alpinux.org`.
|
||||
Appartient à `web17:client1` (`drwx--x---`) — `sudo rsync` requis pour y écrire.
|
||||
|
||||
### ACL pour l'app Flask
|
||||
|
||||
Le service tourne en tant qu'`abonnelc` qui n'est ni `web17` ni dans `client1`.
|
||||
Une ACL POSIX lui donne les droits de lecture nécessaires :
|
||||
|
||||
```bash
|
||||
sudo setfacl -R -m u:abonnelc:rx /var/www/clients/client1/web17/web
|
||||
sudo setfacl -d -m u:abonnelc:rx /var/www/clients/client1/web17/web
|
||||
```
|
||||
|
||||
ISPConfig peut réinitialiser les permissions du web root lors d'une modification du site —
|
||||
relancer ces deux commandes si le tableau de bord retourne une `PermissionError`.
|
||||
|
||||
## Statistiques GoAccess
|
||||
|
||||
### Génération manuelle
|
||||
|
||||
```bash
|
||||
sudo goaccess /var/log/ispconfig/httpd/static.alpinux.org/access.log \
|
||||
--log-format=COMBINED --no-global-config \
|
||||
--output=/opt/static-cdn/goaccess.html
|
||||
sudo goaccess /var/log/ispconfig/httpd/static.alpinux.org/access.log \
|
||||
--log-format=COMBINED --no-global-config \
|
||||
--output=/opt/static-cdn/goaccess.json
|
||||
sudo chown abonnelc: /opt/static-cdn/goaccess.html /opt/static-cdn/goaccess.json
|
||||
```
|
||||
|
||||
### Cron quotidien (root)
|
||||
|
||||
```cron
|
||||
0 4 * * * goaccess /var/log/ispconfig/httpd/static.alpinux.org/access.log \
|
||||
--log-format=COMBINED --no-global-config \
|
||||
--output=/opt/static-cdn/goaccess.html && \
|
||||
goaccess /var/log/ispconfig/httpd/static.alpinux.org/access.log \
|
||||
--log-format=COMBINED --no-global-config \
|
||||
--output=/opt/static-cdn/goaccess.json && \
|
||||
chown abonnelc: /opt/static-cdn/goaccess.html /opt/static-cdn/goaccess.json
|
||||
```
|
||||
|
||||
Le rapport JSON alimente les **badges "Vues"** dans le navigateur de fichiers (browse).
|
||||
Sans ce fichier, les badges sont masqués.
|
||||
|
||||
## Accès rsync (assets CDN)
|
||||
|
||||
Les assets sont synchronisés via `static/scripts/push-assets.sh` / `pull-assets.sh`.
|
||||
Le dossier `app/` est exclu du rsync (déployé séparément, non servi depuis le web root).
|
||||
Loading…
Reference in a new issue