# org.alpinux.owni Accueil des projets de l'association **Alpinux** (le LUG de Savoie). Chaque sous-dossier est un dépôt git indépendant avec son propre remote sur Gitea. Ce dossier racine est l'espace de travail : son dépôt [alpinux-owni](https://gitea.alpinux.org/alpinux.cedrica5l/alpinux-owni) ne versionne que ce `README.md` et le `.gitignore` — le contenu des sous-dossiers appartient à leur dépôt. --- ## Projets | Dossier | Domaine | Technologie | Dépôt Gitea | |---------|---------|-------------|-------------| | `feedback/` | feedback.alpinux.org | à construire | [alpinux-feedback](https://gitea.alpinux.org/alpinux.cedrica5l/alpinux-feedback) | | `home/` | alpinux.org | HTML statique | [alpinux-home](https://gitea.alpinux.org/alpinux.cedrica5l/alpinux-home) | | `portail/` | portail.alpinux.org | en construction | [alpinux-portail](https://gitea.alpinux.org/alpinux.cedrica5l/alpinux-portail) | | `infra/` | — | Configs Apache + systemd | [alpinux-infra](https://gitea.alpinux.org/alpinux.cedrica5l/alpinux-infra) | ### Sortis de cet espace Ces projets ont leur propre dossier, au même niveau que celui-ci — un dépôt, un dossier : | Dossier | Domaine | Dépôt Gitea | |---------|---------|-------------| | `~/Projects/alpinux.wiki` | wiki.alpinux.org | [alpinux-wiki](https://gitea.alpinux.org/alpinux.cedrica5l/alpinux-wiki) | | `~/Projects/alpinux.admin` | admin.alpinux.org | [alpinux-admin](https://gitea.alpinux.org/alpinux.cedrica5l/alpinux-admin) | | `~/Projects/alpinux.dynamic` | dynamic.alpinux.org | [alpinux-dynamic](https://gitea.alpinux.org/alpinux.cedrica5l/alpinux-dynamic) | | `~/Projects/alpinux.static` | static.alpinux.org | [alpinux-static](https://gitea.alpinux.org/alpinux.cedrica5l/alpinux-static) | | `~/Projects/alpinux.gitea` | gitea.alpinux.org | [alpinux-gitea](https://gitea.alpinux.org/alpinux.cedrica5l/alpinux-gitea) | | `~/Projects/alpinux.messagerie` | messagerie.alpinux.org | [alpinux.messagerie](https://gitea.alpinux.org/alpinux.cedrica5l/alpinux.messagerie) | Leurs procédures de déploiement sont décrites dans leur propre README. > **La messagerie ne se déploie pas comme les autres.** owni n'en est pas un > clone : la mise à jour s'y fait par **copie de fichiers, base d'abord, code > ensuite**, et non par `git pull`. La procédure et les pièges qu'elle > désamorce sont dans `docs/installation.md` de ce dépôt. En service depuis le > 22/09/2026 — 256 abonnés, un worker appelé chaque minute, trois boîtes > relevées en IMAP : ce qui casse casse pour de vrai. Gitea : **https://gitea.alpinux.org/alpinux.cedrica5l** ISPConfig : **https://owni.alpinux.org:8080** AlpID (SSO) : **https://alpid.alpinux.org** — realm `master` --- ## Procédure de déploiement ### Vue d'ensemble | Projet | Méthode | Commande | |--------|---------|----------| | `home` | git pull sur serveur | `ssh alpinux.org "cd && git pull"` | | `static` (app) | rsync local + restart | `cd ~/Projects/alpinux.static && scripts/deploy-app.sh` | | `static` (assets) | rsync local | `cd ~/Projects/alpinux.static && scripts/push-assets.sh` | Dans tous les cas : versionner avec `git push` **avant** de déployer. ### static.alpinux.org Le détail (app Flask et assets CDN) est dans `~/Projects/alpinux.static/README.md`. ```bash cd ~/Projects/alpinux.static git push origin main # versionner d'abord scripts/deploy-app.sh # app Flask → /opt/static-cdn + restart service scripts/push-assets.sh # logo/, wiki/, stats/, error/ → web root ISPConfig ``` ### Wiki Rien à faire : un webhook Gitea construit et met en ligne à chaque push sur `main`. Voir https://wiki.alpinux.org/technique/deploiement-wiki/ --- ## Développement local | Projet | Commande | URL | |--------|----------|-----| | `~/Projects/alpinux.static` | `python app/app.py` | http://localhost:5003 | ```bash cd python3 -m venv venv && source venv/bin/activate pip install -r requirements.txt cp .env.example .env && nano .env flask run --port ``` --- ## Authentification AlpID Tous les projets Flask utilisent **AlpID** (SSO Keycloak). - Chaque projet a son propre client Keycloak (`admin`, `dynamic`, `static-cdn`, …) - Scopes : `openid profile email` - Autorisation : claim `groups` → sinon `ADMIN_EMAILS` → sinon tout utilisateur AlpID - Discovery URL : `https://alpid.alpinux.org/realms/master/.well-known/openid-configuration` --- ## Credentials locaux Le fichier **`.credentials`** (ignoré par git) centralise les accès à renseigner localement : ``` .credentials ← à compléter manuellement, jamais commité ``` Il contient : token Gitea API, accès ISPConfig, accès AlpID admin, secrets clients Keycloak. Utiliser `source .credentials` dans un script pour charger les variables. --- ## Règle Claude Code Lancer Claude depuis le sous-dossier du projet pour limiter le contexte : ```bash cd ~/Projects/alpinux.static && claude cd ~/Projects/alpinux.wiki && claude ``` --- ## Comptes personnels vs comptes de service Alias SSH : `alpinux.org` → compte `abonnelc`. ### Règle absolue Un compte personnel (`abonnelc` ou tout autre) ne doit jouer **aucun rôle dans le fonctionnement à long terme** des services : - pas `User=` dans un unit systemd - pas propriétaire des fichiers de l'app ou des logs - pas dans la liste des groupes dont dépend un service en production - pas référencé dans un `chown`, `setfacl`, ou cron de production Si un service dépend d'un compte personnel, sa disparition (départ, suppression du compte, changement de login) fait tomber le service en production. ### Rôle d'abonnelc `abonnelc` est un **compte d'administration ponctuelle**, limité à : - créer ou modifier les fichiers `.env` sur le serveur - redémarrer un service après un déploiement - effectuer des opérations admin exceptionnelles ### Comptes de service Chaque service tourne sous son propre utilisateur système dédié (ex. `static-cdn` pour `static-cdn.service`). C'est ce compte qui possède les fichiers, les logs, et les droits nécessaires — pas `abonnelc`. --- ## Serveur | | | |---|---| | **Hostname** | `owni.alpinux.org` | | **OS** | Debian 12 (bookworm) | | **IPv4** | `51.91.79.148` | | **IPv6** | `2001:41d0:404:200::3f85/128` | | **Passerelle IPv6** | `2001:41d0:404:200::1` | | **SSH** | `ssh alpinux.org` (alias → `abonnelc@owni.alpinux.org`) | Config IPv6 persistante : `/etc/network/interfaces.d/60-ipv6.cfg` Cloud-init réseau désactivé : `/etc/cloud/cloud.cfg.d/99-disable-network-config.cfg` --- ## Courrier sortant : tout passe par un relais **Depuis les 25-26 septembre 2026**, Postfix ne remet plus directement aux destinataires : `relayhost = [mail.acemail.fr]:587`, en soumission authentifiée. | | | |---|---| | **IP qui parle aux destinataires** | `176.9.125.188` (le relais), et non plus `51.91.79.148` | | **SPF** | `v=spf1 a mx include:_spf.acemail.fr -all` | | **DKIM** | signé par owni **avant** la remise au relais | | **DMARC** | `p=quarantine`, `rua=mailto:postmaster@alpinux.org` | Trois conséquences qu'il vaut mieux connaître avant de chercher ailleurs : - **La réputation d'expéditeur n'est plus la nôtre seule.** Un rejet de plus compte contre une IP partagée avec les autres clients de l'hébergeur. - **Un plafond d'envoi s'ajoute à celui de Postfix**, celui du relais, et il n'est pas connu à ce jour. Le franchir se verrait en `status=deferred` dans `/var/log/mail.log`, avec un code `4.x.x` venu du relais. - **L'enveloppe doit survivre au relais.** La messagerie utilise des adresses de retour variables (`bounce+@alpinux.org`) pour identifier les non-remises. Vérifié le 27/09 : le relais les préserve. À revérifier après tout changement chez l'hébergeur — la panne serait silencieuse, les rebonds cessant simplement d'arriver. --- ## Bases de données Six bases applicatives, déclarées dans ISPConfig, plus celles du système. | Base | Service | Sauvegarde | |---|---|---| | `c1_messagerie_db` | messagerie.alpinux.org | quotidienne, **1 copie** | | `c1dolibarr` | dolibarr.alpinux.org — fichier des adhérents | **aucune** | | `c1gitea` | gitea.alpinux.org — tous les dépôts | **aucune** | | `c1alpid` | alpid.alpinux.org — le SSO | **aucune** | | `c1_installparty` | installparty.alpinux.org | **aucune** | | `c1_evenements` | événements | **aucune** | S'y ajoutent `dbispconfig`, `roundcube` et `phpmyadmin`. `sudo mysql` passe par le socket unix, sans mot de passe. --- ## Sauvegardes : ce qui est couvert, et ce qui ne l'est pas État au 27/09/2026, à corriger — voir le ticket [#1](https://gitea.alpinux.org/alpinux.cedrica5l/alpinux-owni/issues/1). - **Une base sur six** est sauvegardée quotidiennement, la messagerie, dans `/var/backup/web21/`. Les cinq autres ne le sont pas, Dolibarr et Gitea compris. - **Une seule copie conservée** (`backup_copies = 1`) : une corruption remarquée deux jours plus tard n'est plus récupérable. - **Les 14 sites sont à `backup_interval = none`** côté fichiers. - **Tout reste sur owni.** Un disque perdu emporte les données et leurs copies. Ce que contient `/var/backup/ispconfig/` ne concerne qu'ISPConfig lui-même. Une sauvegarde qu'on n'a jamais restaurée est une hypothèse, pas une garantie. --- ## Infra `infra/` est un dépôt git indépendant ([alpinux-infra](https://gitea.alpinux.org/alpinux.cedrica5l/alpinux-infra)). Il contient les configurations de référence pour audit et reconstruction : ``` infra/ ├── conf/ → VirtualHost Apache par service ├── services/ → Units systemd └── docs/ → Documentation déploiement par service ``` ne pas mentionner "sonnet" ou "claude"