Rendre aux sites la documentation de leur déploiement
Cinq documents décrivaient ici le déploiement de sites, pas la machine : admin, static, wiki, dynamic et le proxy de calendrier d'alpinux.org. Ils avaient exactement la place qu'on vient de refuser à la messagerie. Chacun rejoint son dépôt — alpinux-admin/DEPLOIEMENT.md, alpinux-dynamic/DEPLOIEMENT.md, alpinux-wiki/docs/deploiement.md, alpinux-static/INFRASTRUCTURE.md, alpinux-home/PROXY-CALENDRIER.md — et le tableau « Déployer un site » dit désormais où chercher plutôt que de le redire. Une documentation de déploiement tenue loin du code qu'elle décrit finit toujours par en diverger : c'est le code qui bouge, pas la page qui le raconte. Restent ici les trois documents qui parlent de la machine : le courrier sortant, les certificats, les sauvegardes. 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
1012c7bd69
commit
6b538c2003
6 changed files with 5 additions and 315 deletions
|
|
@ -46,10 +46,13 @@ garantirait qu'elles divergent.
|
||||||
|
|
||||||
| Projet | Où est la procédure |
|
| Projet | Où est la procédure |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `static` | `alpinux-static/README.md` — `scripts/deploy-app.sh`, `scripts/push-assets.sh` |
|
| `static` | `alpinux-static/README.md` et `INFRASTRUCTURE.md` |
|
||||||
| `wiki` | webhook Gitea à chaque push ; <https://wiki.alpinux.org/technique/deploiement-wiki/> |
|
| `wiki` | `alpinux-wiki/docs/deploiement.md` ; webhook Gitea à chaque push |
|
||||||
| `home` | `git pull` sur le serveur |
|
| `home` | `git pull` sur le serveur |
|
||||||
| `messagerie` | `alpinux.messagerie/docs/installation.md` — **copie de fichiers, base d'abord** |
|
| `messagerie` | `alpinux.messagerie/docs/installation.md` — **copie de fichiers, base d'abord** |
|
||||||
|
| `admin` | `alpinux-admin/DEPLOIEMENT.md` |
|
||||||
|
| `dynamic` | `alpinux-dynamic/DEPLOIEMENT.md` |
|
||||||
|
| `home` | `git pull` sur le serveur ; le proxy de calendrier est décrit dans `alpinux-home/PROXY-CALENDRIER.md` |
|
||||||
| autres | le README du dépôt concerné |
|
| autres | le README du dépôt concerné |
|
||||||
|
|
||||||
Dans tous les cas : versionner avec `git push` **avant** de déployer.
|
Dans tous les cas : versionner avec `git push` **avant** de déployer.
|
||||||
|
|
@ -174,7 +177,6 @@ OVH, sinon il décrit un état qui n'existe plus.
|
||||||
| [`docs/courrier-sortant.md`](docs/courrier-sortant.md) | relais, SPF/DKIM/DMARC, plafonds, boîtes du service |
|
| [`docs/courrier-sortant.md`](docs/courrier-sortant.md) | relais, SPF/DKIM/DMARC, plafonds, boîtes du service |
|
||||||
| [`docs/certificats.md`](docs/certificats.md) | les deux mécanismes TLS, leurs pièges, les réparations |
|
| [`docs/certificats.md`](docs/certificats.md) | les deux mécanismes TLS, leurs pièges, les réparations |
|
||||||
| [`docs/sauvegardes.md`](docs/sauvegardes.md) | sauvegarder les bases, et surtout les restaurer |
|
| [`docs/sauvegardes.md`](docs/sauvegardes.md) | sauvegarder les bases, et surtout les restaurer |
|
||||||
| `docs/admin.md`, `docs/static.md`, `docs/wiki.md`, `docs/dynamic.md`, `docs/proxy-calendar.md` | déploiement par service — à rapatrier dans leurs dépôts |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
# admin.alpinux.org
|
|
||||||
|
|
||||||
Interface d'administration Alpinux — Flask + AlpID SSO.
|
|
||||||
|
|
||||||
## Déploiement
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd org.alpinux.owni/admin
|
|
||||||
git pull
|
|
||||||
source venv/bin/activate
|
|
||||||
pip install -r requirements.txt
|
|
||||||
sudo systemctl restart alpinux-admin
|
|
||||||
```
|
|
||||||
|
|
||||||
## Variables d'environnement (`/opt/alpinux-admin/.env`)
|
|
||||||
|
|
||||||
| Variable | Obligatoire | Description |
|
|
||||||
|----------|-------------|-------------|
|
|
||||||
| `SECRET_KEY` | oui | Clé Flask (`python3 -c "import secrets; print(secrets.token_hex(32))"`) |
|
|
||||||
| `ALPID_CLIENT_ID` | oui | Client Keycloak |
|
|
||||||
| `ALPID_CLIENT_SECRET` | oui | Secret Keycloak |
|
|
||||||
| `ALPID_DISCOVERY_URL` | oui | `https://alpid.alpinux.org/realms/master/.well-known/openid-configuration` |
|
|
||||||
| `ADMIN_GROUPS` | non | Groupes autorisés (défaut : `admins`) |
|
|
||||||
| `ADMIN_EMAILS` | non | Emails autorisés (fallback si `groups` absent du token) |
|
|
||||||
|
|
||||||
## Apache — directives proxy
|
|
||||||
|
|
||||||
```apache
|
|
||||||
RequestHeader set X-Forwarded-Proto "https"
|
|
||||||
ProxyPreserveHost On
|
|
||||||
ProxyPass / http://127.0.0.1:5001/
|
|
||||||
ProxyPassReverse / http://127.0.0.1:5001/
|
|
||||||
```
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
# dynamic.alpinux.org
|
|
||||||
|
|
||||||
Quiz et jeux — Flask + AlpID SSO.
|
|
||||||
|
|
||||||
## Déploiement
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd org.alpinux.owni/dynamic
|
|
||||||
git pull
|
|
||||||
source venv/bin/activate
|
|
||||||
pip install -r requirements.txt
|
|
||||||
sudo systemctl restart dynamic.alpinux.org
|
|
||||||
```
|
|
||||||
|
|
||||||
## Variables d'environnement
|
|
||||||
|
|
||||||
| Variable | Obligatoire | Description |
|
|
||||||
|----------|-------------|-------------|
|
|
||||||
| `SECRET_KEY` | oui | Clé Flask |
|
|
||||||
| `ALPID_CLIENT_ID` | oui | Client Keycloak |
|
|
||||||
| `ALPID_CLIENT_SECRET` | oui | Secret Keycloak |
|
|
||||||
| `ALPID_DISCOVERY_URL` | oui | `https://alpid.alpinux.org/realms/master/.well-known/openid-configuration` |
|
|
||||||
|
|
||||||
## Apache — directives proxy
|
|
||||||
|
|
||||||
```apache
|
|
||||||
RequestHeader set X-Forwarded-Proto "https"
|
|
||||||
ProxyPreserveHost On
|
|
||||||
ProxyPass / http://127.0.0.1:5000/
|
|
||||||
ProxyPassReverse / http://127.0.0.1:5000/
|
|
||||||
```
|
|
||||||
|
|
@ -1,69 +0,0 @@
|
||||||
# Proxy cache calendrier public — `alpinux.org/public-calendars/`
|
|
||||||
|
|
||||||
## Rôle
|
|
||||||
|
|
||||||
Ce composant expose le calendrier Nextcloud d'Alpinux en iCal public, avec mise en cache locale pour éviter de solliciter le serveur Nextcloud à chaque requête.
|
|
||||||
|
|
||||||
## Localisation
|
|
||||||
|
|
||||||
| Élément | Chemin |
|
|
||||||
|---|---|
|
|
||||||
| Script PHP | `/var/www/clients/client1/web11/web/public-calendars/index.php` |
|
|
||||||
| Cache ICS | `/var/www/clients/client1/web11/web/public-calendars/{token}.ics` |
|
|
||||||
| Lien symlink | `/var/www/alpinux.org/web/` → même racine |
|
|
||||||
|
|
||||||
## Flux de données
|
|
||||||
|
|
||||||
```
|
|
||||||
Visiteur / JS page d'accueil
|
|
||||||
│
|
|
||||||
▼
|
|
||||||
GET https://alpinux.org/public-calendars/{token}
|
|
||||||
│
|
|
||||||
▼
|
|
||||||
index.php
|
|
||||||
├── Cache valide (< 1 h) ? ──▶ sert le fichier .ics local
|
|
||||||
└── Cache expiré ou absent ──▶ fetch Nextcloud DAV
|
|
||||||
│
|
|
||||||
▼
|
|
||||||
https://alpinux.yourownnet.fr/remote.php/dav/public-calendars/{token}?export
|
|
||||||
│
|
|
||||||
▼
|
|
||||||
Écrit {token}.ics ──▶ sert le fichier
|
|
||||||
```
|
|
||||||
|
|
||||||
## TTL du cache
|
|
||||||
|
|
||||||
**3 600 secondes (1 heure).** Passé ce délai, la prochaine requête déclenche un nouveau fetch Nextcloud et écrase le fichier.
|
|
||||||
|
|
||||||
## Modes d'accès
|
|
||||||
|
|
||||||
| URL | Comportement |
|
|
||||||
|---|---|
|
|
||||||
| `/public-calendars/{token}` | Flux iCal brut (usage principal) |
|
|
||||||
| `/public-calendars/{token}?p=webcal` | Redirige vers `webcal://…` pour abonnement depuis une appli calendrier |
|
|
||||||
| `/public-calendars/{token}?p=html` | Aperçu HTML des 8 prochains événements (dans les 4 mois) |
|
|
||||||
|
|
||||||
## Invalidation manuelle du cache
|
|
||||||
|
|
||||||
Lorsqu'un événement est ajouté ou modifié dans Nextcloud et doit apparaître immédiatement (sans attendre 1 heure) :
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo rm /var/www/clients/client1/web11/web/public-calendars/n5BWPYsxw7FCYozM.ics
|
|
||||||
```
|
|
||||||
|
|
||||||
La prochaine requête HTTP sur `/public-calendars/n5BWPYsxw7FCYozM` régénère le cache automatiquement.
|
|
||||||
|
|
||||||
## Token du calendrier Alpinux
|
|
||||||
|
|
||||||
| Calendrier | Token |
|
|
||||||
|---|---|
|
|
||||||
| Alpinux évènements (`president@alpinux.org`) | `n5BWPYsxw7FCYozM` |
|
|
||||||
|
|
||||||
## Source Nextcloud
|
|
||||||
|
|
||||||
Le calendrier est géré dans l'interface Nextcloud de l'association. L'événement doit impérativement être placé dans le calendrier **« Alpinux évènements »** pour apparaître dans le flux public. Un événement dans un autre agenda (personnel, secondaire) ne sera pas exporté.
|
|
||||||
|
|
||||||
## Relation avec la page d'accueil
|
|
||||||
|
|
||||||
`alpinux.org/index.html` charge le flux via `fetch('/public-calendars/n5BWPYsxw7FCYozM')` côté client (JS) pour alimenter la grille planning et les cartes « Prochains rendez-vous ». Voir `home/index.html` pour le code de parsing iCal.
|
|
||||||
156
docs/static.md
156
docs/static.md
|
|
@ -1,156 +0,0 @@
|
||||||
# infra/static — static.alpinux.org
|
|
||||||
|
|
||||||
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).
|
|
||||||
23
docs/wiki.md
23
docs/wiki.md
|
|
@ -1,23 +0,0 @@
|
||||||
# wiki.alpinux.org
|
|
||||||
|
|
||||||
Documentation publique Alpinux — MkDocs Material.
|
|
||||||
|
|
||||||
## Déploiement
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd org.alpinux.owni/wiki
|
|
||||||
mkdocs build --strict
|
|
||||||
rsync -rlcz --delete site/ alpinux.org:/var/www/wiki.alpinux.org/web/
|
|
||||||
```
|
|
||||||
|
|
||||||
## Développement local
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pip install mkdocs-material
|
|
||||||
mkdocs serve # http://localhost:8000
|
|
||||||
```
|
|
||||||
|
|
||||||
## Notes
|
|
||||||
|
|
||||||
- Pas de service systemd — site statique servi directement par Apache
|
|
||||||
- Les docs publiques sont dans `wiki/docs/technique/`
|
|
||||||
Loading…
Reference in a new issue