diff --git a/README.md b/README.md index da7db53..c98543d 100644 --- a/README.md +++ b/README.md @@ -46,10 +46,13 @@ garantirait qu'elles divergent. | Projet | Où est la procédure | |---|---| -| `static` | `alpinux-static/README.md` — `scripts/deploy-app.sh`, `scripts/push-assets.sh` | -| `wiki` | webhook Gitea à chaque push ; | +| `static` | `alpinux-static/README.md` et `INFRASTRUCTURE.md` | +| `wiki` | `alpinux-wiki/docs/deploiement.md` ; webhook Gitea à chaque push | | `home` | `git pull` sur le serveur | | `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é | 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/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/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 | --- diff --git a/docs/admin.md b/docs/admin.md deleted file mode 100644 index 9d5dd06..0000000 --- a/docs/admin.md +++ /dev/null @@ -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/ -``` diff --git a/docs/dynamic.md b/docs/dynamic.md deleted file mode 100644 index bb64e2d..0000000 --- a/docs/dynamic.md +++ /dev/null @@ -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/ -``` diff --git a/docs/proxy-calendar.md b/docs/proxy-calendar.md deleted file mode 100644 index dbaf5c1..0000000 --- a/docs/proxy-calendar.md +++ /dev/null @@ -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. diff --git a/docs/static.md b/docs/static.md deleted file mode 100644 index 7c8a954..0000000 --- a/docs/static.md +++ /dev/null @@ -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). diff --git a/docs/wiki.md b/docs/wiki.md deleted file mode 100644 index 49e9d1a..0000000 --- a/docs/wiki.md +++ /dev/null @@ -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/`