# Serveur sans.pub Lorsque tu interroges le serveur, ne lances que des commandes en LECTURE SEULE (non destructrices). Sauf à la demande explicite de l'utilisateur. ## Accès - **SSH**: `ssh zuck@sans.pub` (alias `~/.ssh/config` : `Host sans.pub`) — sudo sans mot de passe. Note : ce document mentionnait auparavant un utilisateur `cloud`, à vérifier/clarifier (voir `install-serveur.md`, le compte créé est `zuck`). - **CapRover**: https://captain.cloud.sans.pub - **Gitea**: `git.sans.pub` (port SSH 2242, `User git` dans `~/.ssh/config`) ## Infrastructure - **OS**: Debian 9 (kernel 4.9.0-12-amd64) - **Docker**: 19.03.12 (mode Swarm) - **Disque**: 914 Go total, ~193 Go utilisés (23%) - **RAM**: 23 Go (~6 Go utilisés, swap quasi vide — vérifié 2026-02-19) ## Structure Caprover - `/captain/data/` - données persistantes - `/captain/generated/` - configs générées - `/captain/temp/` - fichiers temporaires ## Services actifs (~40 services) ### Outils collaboratifs - **etherpad** - éditeur collaboratif - **ethercalc** - tableur collaboratif - **cryptpad** - suite bureautique chiffrée - **nextcloud** - cloud personnel ### Développement - **gitea** - forge Git - **adminer** - gestion BDD ### Communication - **writefreely** - blog - **peertube** - vidéos - **rss** + **rss-bridge** - flux RSS ### Sécurité/Outils - **bitwarden** - gestionnaire mots de passe - **privatebin** - partage de texte chiffré - **ots** - secrets temporaires - **it-tools** - boîte à outils - **cyberchef** - manipulation de données ### Sites perso - **pierre-martin** - site perso - **sans-pub-site** - site principal - **une-espace** - autre projet ### Enquêtes - **limesurvey** - sondages ## Services en erreur Aucun service en erreur connu (vérifié 2026-02-19). `mail` tourne correctement (1/1, poste.io). ## Commandes et skills Claude ### Commande - `/supervision` - analyse complète de la santé du serveur (invocation manuelle) ### Skill (auto-activé) - `caprover` - gestion des apps via API CapRover - `list` : lister les apps - `info NOM` : détails d'une app - `env NOM` : variables d'environnement - `scale NOM N` : changer le nombre d'instances - `restart NOM` : redémarrer une app **Prérequis** : définir `CAPROVER_PASSWORD` dans `.env` (voir `.envrc`) ### CLI CapRover (alternative à l'API brute) Installé localement via `fnm` (Node géré sans toucher au système) : ```bash curl -fsSL https://fnm.vercel.app/install | bash # une seule fois fnm install --lts && fnm use lts-latest npm install -g caprover caprover login # à faire soi-même dans un vrai terminal (TTY requis pour le mot de passe) ``` Ensuite : `caprover list` (machines connectées), `caprover api -n -t /chemin/api -m GET -d '{}'` pour des appels génériques (toujours passer `-d` même vide, sinon prompt interactif qui plante sans TTY). Endpoints utiles : - `GET /user/apps/appDefinitions` → liste toutes les apps avec `envVars`, `volumes`, `ports`, etc. - `POST /user/apps/appDefinitions/update` (payload : `appName` + les champs à conserver/modifier) → met à jour la config d'une app **sans redéployer l'image** (mais redémarre le service) ⚠️ **`appDefinitions/update` remplace, ne fusionne pas** : un champ absent du payload est réinitialisé à sa valeur par défaut (vécu en prod le 2026-09-23 : `containerHttpPort` oublié → réinitialisé à `80` au lieu de `3000` → 502 sur git.sans.pub pendant plusieurs minutes, cf `incidents/2026-09-14-gitea-cryptominer.md`). **Toujours faire un `GET /user/apps/appDefinitions` juste avant et renvoyer l'objet complet**, en ne modifiant que le(s) champ(s) voulu(s). ## Gitea — détails techniques - **Containers Docker** (Swarm) : `srv-captain--gitea.1.*` (gitea/gitea:1.27.3, mis à jour le 2026-09-23) + `srv-captain--gitea-db.1.*` (mysql:5.7) - **Volume de données** : `captain--gitea-data` → monté sur `/data` dans le container - Dépôts bare : `/data/git/repositories//.git` - Config app : `/data/gitea/conf/app.ini` (contient des secrets en clair : `INTERNAL_TOKEN`, `LFS_JWT_SECRET`, mot de passe MySQL — jamais versionner ce fichier) - `.gitconfig` global (compte système utilisé par Gitea pour exécuter git) : `/data/gitea/home/.gitconfig` - Logs applicatifs : `/data/gitea/log/gitea.log` (rotation quotidienne en `.gz`) - **Réseau** : container Gitea sur `captain-overlay-network`, IP interne observée `10.0.1.75`. Le reverse-proxy CapRover (`captain-nginx`) apparaît côté Gitea sous l'IP `10.0.1.105` pour toutes les requêtes publiques (pas d'IP client réelle sans config `X-Forwarded-For`/trusted proxies). - **Connexion à la base MySQL depuis le host/container** : passer par `-h 127.0.0.1` (TCP), pas par défaut socket local (`localhost`) — le grant MySQL de l'utilisateur `gitea` ne couvre que `%`/TCP, pas `localhost`. - **Variables d'env CapRover de l'app `gitea`** (vérifié via `docker service inspect srv-captain--gitea`) : `DB_HOST`, `DB_PASSWD`, `DB_TYPE`, `DB_USER`, `RUN_MODE`. ⚠️ Aucune n'est au format `GITEA__
__` attendu par l'image officielle pour réinjecter dans `app.ini` au démarrage — elles sont donc **inertes** pour Gitea (c'est `app.ini` dans le volume qui fait foi). En cas de rotation de secret (mot de passe DB notamment), mettre à jour `app.ini` + redémarrer suffit fonctionnellement ; penser quand même à resynchroniser `DB_PASSWD` côté CapRover pour ne pas laisser une copie obsolète du secret. - **⚠️ Voir `incidents/2026-09-14-gitea-cryptominer.md`** : l'API interne Gitea (`/api/internal/manager/add-logger`) a été exploitée pour injecter des `packObjectsHook` malveillants dans `.gitconfig`. Toujours vérifier ce fichier ne contient pas d'entrées `[uploadpack] packObjectsHook` inattendues. ## Backup - **Système actuel (depuis le 2026-10-03)** : restic 0.19.1 (`/usr/local/bin/restic`) → OVH Swift, conteneur `sans-pub-restic` (même projet OVH que l'ancien backup, région GRA) - Script : `/root/restic/backup.sh` (source versionnée : `backup/restic-backup.sh` dans ce dépôt), cron `/etc/cron.d/restic-backup` à 03:30 - Config : `/root/restic/env` (identifiants OVH) + `/root/restic/password` (mot de passe du dépôt) — `600`, **jamais afficher**. Le mot de passe doit aussi être dans Vaultwarden, sinon le backup est inutilisable si le serveur disparaît - Contenu : dumps SQL de toutes les bases (`/var/backups/sans-pub-db/`, détection auto MySQL/MariaDB/PostgreSQL), volumes Docker (hors registres, previews et logs Nextcloud), `/captain/data` (hors registry), `/home/cloud/apps_data`, `/root/backup`, `/etc`. Les fichiers bruts d'une base sont exclus **seulement si son dump a réussi** (sinon sauvegardés en repli) - Particularités des bases : `limesurvey-mariadb-db` n'accepte root qu'en TCP (`-h127.0.0.1`, le mot de passe de `root@localhost` est différent) ; `writefreely-db` a une table `mysql.proc` incompatible (dump sans `--routines`). Le script essaie automatiquement ces variantes - Premier snapshot complet : 2026-10-03 (~53 Gio, ~45 Gio stockés) ; restauration testée (`restic dump` + comparaison SHA256) - ⚠️ Les scripts lancés par `/etc/cron.d/` n'ont que `PATH=/usr/bin:/bin` : d'où le `export PATH=...` en tête des scripts (restic dans `/usr/local/bin` → backups du 4 et 5 octobre 2026 en échec). Tester un script cron avec `systemd-run -E PATH=/usr/bin:/bin