Le livre de Claude
Pages de scripts et d'études de Claude Code sur le PC Elio+Jux
- 0_Claude et le Jux_VPS
- A_liens entre Claude et le KDRIVE
- B_les procédures de Claude
- C_ installation de Claude Code dans le VPS juxjux
- 00_Recapitulatif
- 01_Portainer
- 02_Bookstack
- 03_Homarr
- 04_Audiobookshelf
- 05_BentoPDF
- 06_Cadvisor
- 07_Calibre-web
- 08_Dozzle
- 09_FileBrowser
- 10_FreshRSS
- 11_Gitea
- 12_Grafana
- 13_Immich
- 14_Jellyfin
- 15_Joplin
- 16_Kavita
- 17_Komga
- 18_Mealie
- 19_Navidrome
- 20_NodeExporter
- 21_Prometheus
- 22_Readeck
- 23_Syncthing
- 24_Yourls
- 25_StirlingPDF
- 26_JDownloader
- 27 - Rustdesk
- D_la solution contacts et calendrier
- E_la gestion du SWAP du VPS par Claude
- 01_Les recherches de Claude
- 01A_Kdrive_les explorations
- 01_Portainer - les explorations
- 02_Bookstack_les explorations
- 03_Homarr_les explorations
- 04_Audiobookshelf_les explorations
- 05_BentoPDF_les explorations
- 06_Cadvisor_les explorations
- 07_Calibre-web_les explorations
- 08_Dozzle_les explorations
- 09_FileBrowser_les explorations
- 10_FreshRSS_les explorations
- 11_Gitea_les explorations
- 12_Grafana_les explorations
- 13_Immich_les explorations
- 14_Jellyfin_les explorations
- 15_Joplin_les explorations
- 16_Kavita_les explorations
- 17_Komga_les explorations
- 18_Mealie_les explorations
- 19_Navidrome_les explorations
- 20_NodeExporter_les explorations
- 21_Prometheus_les explorations
- 22_Readeck_les explorations
- 23_Syncthing_les explorations
- 24_Yourls_les explorations
- 25_StirlingPDF
- 02_Claude et le NAS
- 260801 - Mon Linux OS sur SASNEXTE
- 260528_Essai sur \\NASMAISON\foxy\Géographie\
- 260611_procédure Komga-PDF par Claude sur StirlingPDF
- 260614 - procedure Joplin-compression
- 260615 - Immich performance
- Montages Rclone Sasnexte et Kdrive
- 260727 - Claude en MCP sur le NASmaison
- 260731-Claude et SASNEXTE sur le PC Elio+Jux
- 03_Claude et Ubuntu
- 05_Claude et les MCP
- Quelles opportunités entre logiciels opensource et les IA
- Retours de Claude et propositions d'intégration
- QGIS MCP
- Inkscape MCP
- LibreOffice MCP
- Compétences Claude_QGIS
- Competences Claude Libre Office
- 04_Claude et le PC Windows Elio+Jux
0_Claude et le Jux_VPS
A_liens entre Claude et le KDRIVE
kDrive API REST — Infomaniak
| Paramètre | Valeur |
|---|---|
| Drive ID | 591617 |
| Token Bearer | cnAZannhRpecgAfsQM7QiO4Vqh37g6Ht_hm4f0E6eDihMRaP2ZckKCmW959T5ST2Nv3qhGlqs0ltpNAb |
| Base URL | https://api.infomaniak.com/3/drive/591617 |
Endpoints fonctionnels
| Méthode | Endpoint | Usage |
|---|---|---|
GET |
/files/{dir_id}/files |
Lister le contenu d'un dossier |
GET |
/files/{file_id} |
Métadonnées d'un fichier |
POST |
/upload?directory_id={id}&file_name={name}&conflict=replace&total_size={bytes} |
Uploader un fichier. conflict=replace écrase le fichier existant de même nom. conflict=version crée une nouvelle version. |
Recovery automatique FUSE — monitor-rclone.sh (2026-06-24)
Le script /home/debian/monitor-rclone.sh (cron */5 * * * *) surveille les 5 mounts rclone et effectue une recovery complète si l'un d'eux est mort.
Fonctionnement
Pour chaque mount (/music, /komga, /livres, /audiobookshelf/audiobooks, /photo) :
timeout 10 ls — si inaccessible : sudo systemctl restart (kdrive-music, kdrive-komga, kdrive-livres, rclone-audiobooks, rclone-photo) Attente 5s + vérification que le mount répond Restart des containers Docker associés : /music → navidrome-navidrome-1 /komga → komga /livres → Kavita /audiobookshelf/audiobooks → audiobookshelf /photo → Immich-SERVER Immich-MICROSERVICES
Le script est silencieux quand tout va bien — il ne logue que les pannes et recoveries. Log : /home/debian/logs/rclone-monitor.log
Avant cette refactorisation, le script lançait un rclone mount direct (en parallèle des services systemd) et ne redémarrait pas les containers — le FUSE était remonté mais Navidrome gardait l'ancienne référence corrompue.
Suppression de fichiers — non fonctionnelle (testé 2026-06-09)
Tous les endpoints suivants retournent {"result":"error","error":{"code":"method_not_found"}} :
DELETE /files/{file_id}POST /files/trashavec body{"file_ids":[id]}POST /files/trashavec body{"ids":[id]}POST /files/{file_id}/trashPUT /files/{file_id}avec{"deleted":true}DELETE /filesavec body{"ids":[id]}
La doc officielle (developer.infomaniak.com) n'est pas accessible publiquement. L'endpoint de suppression reste inconnu.
Stratégie de rétention — rotation par jour de la semaine
Puisque la suppression via API ne fonctionne pas, le script de backup utilise une rotation par jour de la semaine (date +%u → 1=lundi … 7=dimanche) avec conflict=replace. Résultat : exactement 7 fichiers max par service, les anciens sont écrasés automatiquement chaque semaine.
Script : /opt/backups/vps_backup.sh — cron : 0 2 * * *
Dossiers kDrive (TOOJUX/jux_vps)
| Service | Dossier ID | Exemple de fichier |
|---|---|---|
| BookStack | 1427916 |
bookstack_db_day1.7z |
| Immich | 1427919 |
immich_db_day1.7z |
| Joplin | 1427920 |
joplin_db_day1.7z (~630 Mo) |
| Mealie | 1427921 |
mealie_db_day1.7z |
| Readeck | 1427922 |
readeck_db_day1.7z |
B_les procédures de Claude
1/ la sauvegarde quotidienne de la base de données Joplin sur Kdrive (sans images)
5/ 260611 - Komga-PDF
6/ 260614 - Joplin-Compression
C_ installation de Claude Code dans le VPS juxjux
Installation de Claude Code dans le VPS juxjux
Objectif
Pouvoir intervenir sur les containers du VPS (redémarrage, diagnostic, logs, fix rapide) depuis un mobile Android en mobilité, via SSH + tmux + Claude Code CLI directement installé sur le VPS.
Prérequis constatés (2026-07-21)
- Node.js : v20.20.2 déjà présent sur le VPS (Debian) — aucune installation nécessaire
- npm : v10.8.2
- tmux : absent, installé via
sudo apt-get install -y tmux(v3.3a-3)
Installation de Claude Code CLI
Installation en local user (pas de sudo npm install -g) pour éviter de faire tourner le CLI en root et éviter les conflits de permissions npm globales :
mkdir -p ~/.npm-global
npm config set prefix '~/.npm-global'
npm install -g @anthropic-ai/claude-code
Ajout du PATH dans ~/.bashrc :
echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.bashrc
Version installée : 2.1.197
Authentification
Choix retenu : login OAuth avec le compte claude.ai (Julien, plan Claude Pro) — pas de clé API Anthropic séparée, donc pas de facturation à l'usage additionnelle.
Procédure suivie (le VPS est headless, pas de navigateur local) :
- Lancer
claudedans une session tmux dédiée (tmux new-session -d -s claude) pour que la session survive à une déconnexion SSH - Choisir "Claude account with subscription" au login
- Le CLI affiche une URL
https://claude.com/cai/oauth/authorize?...— impossible à ouvrir depuis le VPS, donc récupérée viatmux capture-paneet ouverte manuellement sur un navigateur (PC ou mobile) - Après connexion sur claude.ai, un code
xxxx#yyyyest retourné — collé dans le promptPaste code here if prompted >viatmux send-keys - Confirmation :
Logged in as julien.bertrand@live.fr
Les credentials sont persistés dans ~/.claude/.credentials.json (permissions 600, debian:debian) — la connexion reste valide pour les sessions futures, pas besoin de se ré-authentifier à chaque lancement.
Usage depuis Android (Termux)
- Installer Termux depuis F-Droid (pas le Play Store, version obsolète)
- Se connecter en SSH au VPS :
ssh debian@51.77.141.54 - Rattacher ou créer la session tmux :
tmux attach -t claude # si la session existe déjà tmux new -s claude # sinon - Lancer
claude(ou il tourne déjà si la session persiste) - Détacher sans tuer la session :
Ctrl+bpuisd— permet de couper la connexion mobile sans interrompre Claude Code
Sécurité
- Le VPS a déjà subi un incident de sécurité (CVE rclone RC, 2026-06-09 — voir page correspondante) : rester vigilant sur toute nouvelle surface d'exposition
- Claude Code tourne en utilisateur
debian(non-root), scope de travail/home/debianaccepté comme dossier de confiance - Authentification liée au compte personnel Julien (Claude Pro) — pas de clé API partagée à protéger séparément
- Accès à la session Claude Code = accès SSH au VPS (mot de passe
debian) — aucune surface réseau supplémentaire ouverte (pas de port exposé, tout passe par SSH existant)
Répertoire de lancement recommandé
Le VPS a déjà en local le CLAUDE.md partagé, synchronisé via Syncthing :
~/Documents/Jux_univers/Claude-pcelio+jux/CLAUDE.md
C'est le même fichier que celui utilisé sur le PC Windows (D:\Syncthing\Jux_univers\Claude-pcelio+jux\CLAUDE.md) et sur Ubuntu. Il fait partie du dossier Syncthing afltj-njyuy ("Tablette VPS Syncthing"), local path ~/Documents.
Lancer claude depuis ce dossier plutôt que /home/debian : le CLI charge automatiquement ce CLAUDE.md et récupère tout le contexte partagé (MCPs, infra, conventions) sans rien reconfigurer.
cd ~/Documents/Jux_univers/Claude-pcelio+jux/
claude
Piège constaté — Syncthing VPS silencieusement déconnecté (2026-07-21)
En vérifiant le CLAUDE.md sur le VPS, le fichier était resté figé au 24 juin alors que la version de référence (PC Windows) avait été mise à jour bien plus récemment (ex. section Inkscape du 21/07).
Diagnostic via le MCP Syncthing :
get_folder_statussur le dossierafltj-njyuyrenvoyaitstate: idle,needBytes: 0,errors: 0— en apparence tout va bien- Mais
get_connections/get_devicesmontraitnumConnections: 0sur tous les appareils — le VPS n'avait aucune connexion active vers ses pairs, y compris PC-Elio+Jux
Autrement dit : Syncthing sur le VPS ne remonte aucune erreur quand il est déconnecté de tout le monde — il affiche juste l'état "idle" du dernier sync connu, ce qui peut faire croire à tort que tout est synchronisé.
Résolution : dès que Syncthing a été relancé côté PC Windows, la connexion TCP vers le VPS (device I4M5WXU) s'est rétablie en quelques secondes, et le CLAUDE.md s'est mis à jour immédiatement (nouveau hash, date du jour).
Point de vigilance pour la suite : si le CLAUDE.md sur le VPS semble périmé, ne pas se fier à get_folder_status seul (peut afficher "idle" à tort) — vérifier get_connections pour confirmer que le VPS a bien une connexion active vers au moins un appareil source avant de creuser plus loin.
Points d'attention pour la suite
- Penser à
/initpour générer un CLAUDE.md propre au contexte VPS si l'usage se confirme - Vérifier que la session tmux ne meurt pas silencieusement (pas de
Restart=alwaystype systemd ici, contrairement aux services rclone)
00_Recapitulatif
260802 - Allegement JVM Komga + StirlingPDF (applique le 2026-08-02 a 22h)
Application des optimisations memoire validees le 2026-08-01, apres verification du backup quotidien (BILAN 5/5 OK).
Les deux stacks ont ete redeployees depuis /home/debian/{komga,stirling}-compose-new.yml,
les composes precedents sauvegardes en .bak-260802.
| Service | Avant | Apres | Resultat |
|---|---|---|---|
| Komga (stack 7) | -Xmx4g -Xms2g -XX:MaxRAMPercentage=70.0limits 4500M / reservations 3000M 707 Mio residents |
-Xmx1glimits 1500M / reservations 256M |
415 Mio (-292 Mio, -41 %) |
| StirlingPDF (stack 89) | JVM sans limite 722 Mio residents |
-Xmx512mlimits 2g |
785 Mio — pas de reduction, mais consommation desormais bornee |
Bilan hote : swap 3,7 Go -> 2,2 Go (-1,5 Go), memoire disponible 4,4 -> 4,6 Gi.
L'essentiel du gain vient de Komga : c'est le -Xms2g qui pre-allouait 2 Go de heap au demarrage.
Pourquoi StirlingPDF ne baisse pas : le process java conserve 799 Mio de RSS malgre
-Xmx512m (512 Mio de heap + non-heap : metaspace, code cache, piles de threads), auxquels s'ajoutent
LibreOffice (soffice.bin, ~98 Mio), unoserver et Xvfb que Stirling lance pour les conversions.
Le benefice obtenu n'est pas une baisse mais un plafond : la consommation ne peut plus deborder.
Limite portee de 1 Go a 2 Go avant application. Le plan initial prevoyait 1 Go. Or l'OCR fait tourner
ocrmypdf et tesseract comme processus Python hors JVM : -Xmx ne les borne pas, seul le plafond cgroup du
container s'applique. Pic mesure a 894-969 Mio pour une seule page A4 300 dpi — un plafond de 1 Go aurait
provoque un OOM kill des le premier OCR. La version 1 Go est conservee en
/home/debian/stirling-compose-new.yml.orig1g mais ne doit pas etre utilisee.
Verifications apres deploiement : Komga repond 200 et son API /api/v1/libraries renvoie bien les
bibliotheques ; StirlingPDF valide ses deux fonctions critiques, compress-pdf (utilise par les workflows
komga-pdf et nas_geo_compress) et l'OCR (page A4 300 dpi, pic 969 Mio, aucun OOM kill, aucun redemarrage).
Piege de deploiement : les projets compose s'appellent 7 et 89 (les IDs de stack Portainer),
pas komga / stirlingpdf. La commande correcte est
sudo docker compose -p 7 -f /var/lib/docker/volumes/portainer_data/_data/compose/7/docker-compose.yml up -d.
Rollback : restaurer le .bak-260802 de la stack concernee et redeployer de la meme facon.
Vue d ensemble - VPS Jux + Claude Code
34 containers en production sur le VPS. 25 pages de documentation, une par service. 13 services disposent d un MCP actif dans Claude Code. Mis a jour le 2026-05-30.
| Page | URL | MCP Claude Code | Statut integration |
|---|---|---|---|
| 01_Portainer | https://portainer.juxjux.ovh | mcp__portainer__* |
MCP actif |
| 02_Bookstack | https://bookstack.juxjux.ovh | bookstack-mcp-server (npm) |
MCP actif |
| 03_Homarr | https://homarr.juxjux.ovh | mcp__homarr__* |
MCP actif |
| 04_Audiobookshelf | https://audiobookshelf.juxjux.ovh | mcp__audiobookshelf__* |
MCP actif |
| 05_BentoPDF | - | - | API directe |
| 06_Cadvisor | - | - | via Prometheus |
| 07_Calibre-web | - | - | OPDS |
| 08_Dozzle | - | - | via Portainer MCP |
| 09_FileBrowser | https://files.juxjux.ovh | mcp__filebrowser__* |
MCP actif |
| 10_FreshRSS | https://freshrss.juxjux.ovh | mcp__freshrss__* |
MCP actif |
| 11_Gitea | - | - | API REST directe |
| 12_Grafana | https://grafana.juxjux.ovh | - | API REST directe |
| 13_Immich | https://immich.juxjux.ovh | mcp__immich__* |
MCP actif (5 containers) |
| 14_Jellyfin | https://jellyfin.juxjux.ovh | mcp__jellyfin__* |
MCP actif |
| 15_Joplin | - | - | sync server uniquement |
| 16_Kavita | https://kavita.juxjux.ovh | mcp__kavita__* |
MCP actif |
| 17_Komga | https://komga.juxjux.ovh | mcp__komga__* |
MCP actif |
| 18_Mealie | https://mealie.juxjux.ovh | mcp__mealie__* |
MCP actif |
| 19_Navidrome | https://navidrome.juxjux.ovh | mcp__navidrome__* |
MCP actif |
| 20_NodeExporter | - | - | via Prometheus |
| 21_Prometheus | - | - | API REST / PromQL |
| 22_Readeck | https://readeck.juxjux.ovh | mcp__readeck__* |
MCP actif |
| 23_Syncthing | https://syncthing.juxjux.ovh | mcp__syncthing__* |
MCP actif |
| 24_Yourls | - | - | API REST directe |
| 25_StirlingPDF | https://spdf.juxjux.ovh | - | API directe |
| A_liens entre Claude et le KDRIVE | kdrive.infomaniak.com | @infomaniak/mcp-server-kdrive + API REST |
MCP actif (kdrive_search) + API directe |
Scripts de maintenance
| fill_bookstack_pages.py | Remplit les pages avec les infos containers (image, ports, volumes) | C:\Users\eliob\.claude\fill_bookstack_pages.py |
|---|---|---|
| fill_bookstack_mcp.py | Ajoute la section integration Claude Code / MCP a chaque page | C:\Users\eliob\.claude\fill_bookstack_mcp.py |
Configuration MCP
Scripts dans C:\Users\eliob\.claude\, enregistres dans C:\Users\eliob\.mcp.json. Projet Claude Code principal : C:\Users\eliob. Endpoint Portainer Docker local : ID 3.
260611-REX VPS par Claude
Releve du 2026-06-11 via Prometheus (PromQL sur localhost:9090) + Portainer MCP.
Etat global
| RAM | 8.4 / 11.41 GB (73.6%) |
|---|---|
| Swap | 3.99 / 4.0 GB (quasi plein) |
| CPU | 5.2% |
Top consommateurs RAM (RSS)
| Container | RAM RSS |
|---|---|
| komga | 1059 MB |
| Immich-SERVER | 1011 MB |
| Immich-MICROSERVICES | 520 MB |
| stirling-pdf | 442 MB |
| homarr2026 | 355 MB |
| jellyfin | 272 MB |
| prometheus | 259 MB |
| jdownloader | 220 MB |
| Kavita | 196 MB |
| joplin | 179 MB |
| calibre-web-eyrolles | 132 MB |
| mealie | 129 MB |
| grafana | 125 MB |
| cadvisor | 91 MB |
| navidrome | 86 MB |
Swap sature : komga + Immich representent ~2.5 GB a eux deux. StirlingPDF (442 MB) reste charge entre les appels.
260801-REX VPS par Claude
Releve du 2026-08-01 via docker stats + /proc en SSH (PC eliob).
Etat global
| RAM | 8.2 / 11.41 GB (71.7%) |
|---|---|
| Swap | 4.0 / 4.0 GB (sature a 100%) |
| CPU | 28% (compression 7z du backup en cours) |
Top consommateurs RAM (RSS)
| Container | RAM RSS |
|---|---|
| Immich-SERVER | 1147 MB |
| komga | 791 MB |
| Immich-MICROSERVICES | 618 MB |
| stirling-pdf | 566 MB |
| jellyfin | 380 MB |
| homarr2026 | 313 MB |
| Immich-DB | 310 MB |
| prometheus | 282 MB |
| joplin | 241 MB |
| Kavita | 240 MB |
| cadvisor | 195 MB |
| grafana | 164 MB |
| joplin-db | 158 MB |
| yourls-db | 157 MB |
| audiobookshelf | 140 MB |
Swap sature : komga (760 MB) + StirlingPDF (406 MB) en tete des processus swappes, Immich ~330 MB. Des limites memoire ont ete posees depuis juin sur les gros containers (komga 4.4G, Immich 2G, Kavita 4G, joplin 2G). Decouvertes du jour : GNOME/gdm3 tourne a vide sur tty1 depuis le 8 juillet (98 paquets installes, ~150 MB RAM, aucun acces distant configure) ; sauvegardes Immich vides depuis l'origine (pg_dump sans -d immich, archives de 4 Ko) — corrigees le 2026-08-01, dump reel 307 MB.
Actions realisees le 2026-08-01 (soir)
| Action | Detail | Gain |
|---|---|---|
| Fix backup Immich | -d immich ajoute dans /opt/backups/vps_backup.sh + run manuel complet 5/5 OK (archive 87 MB sur kDrive, premiere sauvegarde Immich valide) |
donnees enfin sauvegardees |
| Fusion Immich | 5 containers → 3 : SERVER unique (API + workers, NODE_OPTIONS=--max-old-space-size=768), MICROSERVICES et LEARNING supprimes (recherche semantique et visages non utilises). Ancien compose : compose/29/docker-compose.yml.bak-260801 |
~900 MB RAM |
| Arret cAdvisor | docker update --restart=no cadvisor + stop. Plus de metriques par container dans Prometheus/Grafana (node-exporter conserve le host) |
~200 MB RAM + 4-8% CPU |
| GDM/GNOME desactive puis purge | gdm3 + gnome-shell + Xorg tournaient a vide sur tty1 depuis le 2026-07-08. systemctl disable --now gdm puis purge apt de 263 paquets (bureau complet + LibreOffice, jeux...). Verifie avant : ens3 gere par systemd-networkd, NetworkManager non critique. Verifie apres : 30 containers up, nginx/docker/ssh/wg actifs, sites en 200 |
~150 MB RAM + 3,5 GB disque |
Resultat global du 2026-08-01 : swap 4,0/4,0 GB (sature depuis juin) → 2,6/4,0 GB ; disque 62% → 59% ; ~1,3 GB de RAM liberes. Immich verifie fonctionnel par Julien.
Plan du 2026-08-02 a 19h (tache planifiee Claude Code)
Apres verification du backup nocturne (BILAN 5/5 OK), appliquer les deux fixes JVM prepares et valides (fichiers en attente dans /home/debian/) :
| Service | Avant | Apres | Gain attendu |
|---|---|---|---|
| Komga (stack 7) | -Xmx4g -Xms2g (2 GB pre-alloues, ~760 MB en swap), limites 4500M/3000M |
-Xmx1g sans Xms, limites 1500M/256M |
~400-500 MB RAM + ~700 MB swap |
| StirlingPDF (stack 89) | JVM sans plafond (566-643 MB residents + ~406 MB swap) | JAVA_TOOL_OPTIONS=-Xmx512m, limite 1g |
~300-400 MB RAM |
Verifications prevues : komga.juxjux.ovh en 200, test compress-pdf sur spdf.juxjux.ovh (fonction critique des workflows komga-pdf et geo_loud), docker stats, free -h (swap attendu sous ~2 GB). Rollback : restaurer les .bak-260802. Nota : BentoPDF n'existe plus sur le VPS (container supprime) — il ne peut de toute facon pas remplacer StirlingPDF (pas d'API serveur, traitement 100% navigateur).
01_Portainer
portainer
Docker container management made simple, with the world’s most popular GUI-based container management platform.
| Image | portainer/portainer-ce:latest |
|---|---|
| Etat | Up 9 hours |
| Reseau | bridge |
| URL | https://portainer.juxjux.ovh |
Ports
| Hote | Container | IP |
|---|---|---|
| 9443 | 9443/tcp | 0.0.0.0 |
| 9443 | 9443/tcp | :: |
| 8000 | 8000/tcp | 0.0.0.0 |
| 8000 | 8000/tcp | :: |
| 9000 | 9000/tcp | 0.0.0.0 |
| 9000 | 9000/tcp | :: |
Volumes
| Source (hote) | Destination | Type | Mode |
|---|---|---|---|
/var/lib/docker/volumes/portainer_data/_data | /data | volume | rw |
/var/run/docker.sock | /var/run/docker.sock | bind | rw |
Integration Claude Code — MCP
| Statut MCP | MCP actif |
|---|---|
| Outils (prefix) | mcp__portainer__ |
| Configuration | Script Python : C:\Users\eliob\.claude\mcp_portainer.py | Projet Claude Code : C:\Users\eliob | Auth : JWT via POST /api/auth, endpoint Docker local ID 3 |
Outils disponibles
list_endpointslist_stacksget_stackget_stack_fileredeploy_stacklist_containersget_containerget_container_logsrestart_containerstart_containerstop_containerlist_images
Ce que nous pouvons faire ensemble
- Lister et inspecter tous les containers et leurs états
- Consulter les logs d'un container en temps réel
- Redémarrer, démarrer ou arrêter un container à la demande
- Lire le fichier docker-compose.yml d'une stack
- Redéployer une stack après modification
- Lister toutes les images Docker disponibles sur le VPS
02_Bookstack
bookstack
[Bookstack](https://github.com/BookStackApp/BookStack) is a free and open source Wiki designed for creating beautiful documentation. Featuring a simple, but powerful WYSIWYG editor it allows for teams to create detailed and useful documentation with ease. Powered by SQL and including a Markdown editor for those who prefer it, BookStack is geared towards making documentation more of a pleasure than a chore. For more information on BookStack visit their website and check it out: https://www.bookstackapp.com
| Image | lscr.io/linuxserver/bookstack:latest |
|---|---|
| Version | v26.03.3-ls256 |
| Etat | Up 9 hours |
| Compose project | bookstack |
| Reseau | bookstack_default |
| URL | https://bookstack.juxjux.ovh |
| Source | https://github.com/linuxserver/docker-bookstack |
Ports
| Hote | Container | IP |
|---|---|---|
| 6875 | 80/tcp | 0.0.0.0 |
| 6875 | 80/tcp | :: |
Volumes
| Source (hote) | Destination | Type | Mode |
|---|---|---|---|
/home/debian/docker/bookstack/app | /config | bind | rw |
bookstack_db
[Mariadb](https://mariadb.org/) is one of the most popular database servers. Made by the original developers of MySQL.
| Image | lscr.io/linuxserver/mariadb:latest |
|---|---|
| Version | 11.4.9-r0-ls212 |
| Etat | Up 9 hours |
| Compose project | bookstack |
| Reseau | bookstack_default |
| URL | https://bookstack.juxjux.ovh |
| Source | https://github.com/linuxserver/docker-mariadb |
Volumes
| Source (hote) | Destination | Type | Mode |
|---|---|---|---|
/home/debian/docker/bookstack/db | /config | bind | rw |
Integration Claude Code — MCP
| Statut MCP | MCP actif |
|---|---|
| Outils (prefix) | bookstack MCP (npm bookstack-mcp-server) |
| Configuration | npm via npx -y bookstack-mcp-server | Projet Claude Code : C:\Users\eliob | Auth : Token ID + Secret en variables d'environnement (.claude.json) |
Outils disponibles
list_booksget_booklist_chaptersget_chapterlist_pagesget_pagecreate_pageupdate_pagesearchget_shelves
Ce que nous pouvons faire ensemble
- Lire et écrire des pages de documentation directement depuis Claude Code
- Créer et organiser des livres, chapitres et pages
- Rechercher du contenu dans toute la base de connaissance
- Auto-documenter des projets ou des sessions de travail
- Mettre à jour cette page et les autres pages containers automatiquement
Sauvegarde de la base de données
Sauvegarde automatique quotidienne de la base MariaDB bookstackapp vers kDrive Infomaniak. Mise en place le 2026-06-01.
Paramètres
| Script | /opt/backups/bookstack_backup.sh |
|---|---|
| Cron | Tous les jours à 2h du matin (0 2 * * *) |
| Base sauvegardée | bookstackapp — container bookstack_db (MariaDB) |
| Taille base (disque) | ~203 Mo |
| Format archive | .7z (compression niveau 5) — ~564 Ko |
| Destination | kDrive Infomaniak — TOOJUX/jux_vps/bookstack (dossier ID 1427916) |
| Rétention | 7 jours glissants (purge automatique des anciens fichiers) |
| Log | /opt/backups/backup.log |
| Nommage fichier | bookstack_db_YYYY-MM-DD.7z |
Fonctionnement du script
- Exécute
mysqldumpdepuis le containerbookstack_dbvers/tmp/ - Compresse en
.7zavec7z(déjà installé sur le VPS) - Upload sur kDrive via l'API REST Infomaniak (
POST /3/drive/{id}/upload) avec le paramètretotal_size - Supprime le fichier temporaire local
- Purge les fichiers kDrive nommés
bookstack_db_*de plus de 7 jours
Consulter les logs
ssh debian@51.77.141.54 "tail -50 /opt/backups/backup.log"Relancer manuellement
ssh debian@51.77.141.54 "bash /opt/backups/bookstack_backup.sh"
03_Homarr
homarr2026
A modern and easy to use dashboard. 30+ integrations. 10K+ icons built in. Authentication out of the box. No YAML, drag and drop configuration.
| Image | ghcr.io/homarr-labs/homarr:latest |
|---|---|
| Version | main |
| Etat | Up 9 hours |
| Compose project | homarr |
| Reseau | homarr_homarr_network |
| URL | https://homarr.juxjux.ovh |
| Source | https://github.com/homarr-labs/homarr |
Ports
| Hote | Container | IP |
|---|---|---|
| 7575 | 3000/tcp | 0.0.0.0 |
| 7575 | 3000/tcp | :: |
Volumes
| Source (hote) | Destination | Type | Mode |
|---|---|---|---|
/etc/localtime | /etc/localtime | bind | ro |
/var/run/docker.sock | /var/run/docker.sock | bind | ro |
/home/debian/docker/homarr2026/icons | /app/public/icons | bind | rw |
/home/debian/docker/homarr2026/appdata | /appdata | bind | rw |
Integration Claude Code — MCP
| Statut MCP | MCP actif |
|---|---|
| Outils (prefix) | mcp__homarr__ |
| Configuration | Script Python : C:\Users\eliob\.claude\mcp_homarr.py | Projet Claude Code : C:\Users\eliob | Auth : cookie NextAuth session (authjs.session-token) |
Outils disponibles
get_all_boardsget_board_itemsget_home_boardget_integrationstrpc_call
Ce que nous pouvons faire ensemble
- Lire la configuration du tableau de bord principal
- Lister les services et widgets configurés
- Consulter les intégrations actives (Jellyfin, Sonarr, etc.)
- Appeler des procédures tRPC personnalisées
Mise a jour disponible (verifie le 2026-07-19)
| Version installee | 0.53 |
|---|---|
| Derniere version | 1.71.0 (2026-07-17) |
| Ecart | Traverse la refonte majeure 1.0 (reecriture complete, ete 2024) + ~70 releases mineures jusqu'a juillet 2026 |
Attention : migration majeure, pas un simple bump
Le projet a ete entierement reecrit en version 1.0 et le depot a change de proprietaire : ghcr.io/ajnart/homarr -> ghcr.io/homarr-labs/homarr. Le stack VPS (homarr2026) utilise deja l'image homarr-labs avec le tag latest et un volume /appdata, donc une partie de la migration structurelle semble deja faite -- a verifier avant de bumper vers un tag fige.
Principaux breaking changes (0.x -> 1.0)
- Variables d'env renommees :
DATABASE_URL->DB_URL(conditionnelle),DOCKER_HOST->DOCKER_HOSTNAMES+DOCKER_PORTS,AUTH_PROVIDER->AUTH_PROVIDERS - Nouvelle variable requise :
SECRET_ENCRYPTION_KEY - Variables supprimees :
DISABLE_ANALYTICS,AUTH_OIDC_TIMEOUT,AUTH_LDAP_ADMIN_GROUP,AUTH_LDAP_OWNER_GROUP,AUTH_OIDC_ADMIN_GROUP,AUTH_OIDC_OWNER_GROUP(gestion des groupes/permissions passee dans l'UI) /datarestructure et deplace vers/appdata(non retrocompatible)/app/data/configs(JSON) et/app/public/iconsabandonnes -- gestion des icones et des configs via l'UI- Support ARM v7 supprime
- Tous les widgets reecrits ; systeme d'integrations passe en asynchrone (fetch en arriere-plan + WebSockets/bus de messages)
- Test de connexion desormais obligatoire avant d'activer une integration
Nouveautes notables depuis la 1.0 (jusqu'a 1.71.0)
- v1.65.0 -- support MCP (integration IA), nouvelles integrations Beszel, Technitium DNS, Uptime Kuma, Audiobookshelf, Paperless-ngx, Navidrome ; widgets personnalises ; sauvegarde/restauration SQLite avec apercu WASM ; cache Redis global
- v1.66.1 -- support des groupes locaux OIDC
- v1.68.0 -- ameliorations de l'interface Beszel (stats en direct)
- v1.69.0 -- menu contextuel (clic droit) sur les widgets avec actions auto-generees, evenements calendrier au survol avec epinglage au clic, stockage de secrets par widget
- v1.70.0 -- integrations Traefik (widget dedie), Bazarr, PatchMon, et monitoring systeme Synology ; widgets media manquants/en file d'attente pour Radarr et Sonarr
- v1.71.0 -- support direction de texte pour le widget notes, bouton de rafraichissement compact sur le widget Docker, tri ameliore des torrents qBittorrent
Etapes de migration recommandees
- Sauvegarder
/home/debian/docker/homarr2026/appdataavant toute action - Exporter la config du dashboard depuis l'UI (fonction export/backup SQLite)
- Verifier les variables d'environnement du compose homarr2026 contre la liste des breaking changes ci-dessus (notamment
SECRET_ENCRYPTION_KEY,DOCKER_HOSTNAMES/DOCKER_PORTS) - Redeployer le stack, puis retester chaque integration (Jellyfin, Sonarr, etc.) -- test de connexion obligatoire en 1.x
- Reimporter la sauvegarde SQLite si necessaire
Sources : github.com/homarr-labs/homarr/releases, homarr.dev/blog - Homarr 1.0
04_Audiobookshelf
audiobookshelf
Self-hosted audiobook and podcast server
| Image | ghcr.io/advplyr/audiobookshelf:latest |
|---|---|
| Version | 2.35.0 |
| Etat | Up (healthy) |
| Compose project | audiobookshelf |
| Reseau | audiobookshelf_audiobookshelf_network |
| URL | https://audiobookshelf.juxjux.ovh |
| Source | https://github.com/advplyr/audiobookshelf |
Ports
| Hote | Container | IP |
|---|---|---|
| 13378 | 80/tcp | 127.0.0.1 |
Volumes
| Source (hote) | Destination | Type | Mode |
|---|---|---|---|
/home/debian/audiobookshelf/config | /config | bind | rw |
/home/debian/audiobookshelf/metadata | /metadata | bind | rw |
/home/debian/audiobookshelf/podcasts | /podcasts | bind | rw |
/home/debian/audiobookshelf/audiobooks | /audiobooks | bind | rw, :shared |
Integration Claude Code — MCP
| Statut MCP | MCP actif |
|---|---|
| Outils (prefix) | mcp__audiobookshelf__ |
| Configuration | Script Python : C:\Users\eliob\.claude\mcp_audiobookshelf.py | Auth : JWT Bearer via POST /login |
Outils disponibles
get_librariesget_libraryget_library_itemsget_library_personalizedget_itemget_item_progressget_podcast_episodesdownload_podcast_episodesget_listening_sessionsget_listening_statsget_mesearch_library
Ce que nous pouvons faire ensemble
- Parcourir la bibliothèque d'audiobooks et de podcasts
- Suivre la progression d'écoute d'un livre ou épisode
- Rechercher un titre, auteur ou podcast
- Consulter les statistiques d'écoute (temps total, sessions)
- Télécharger des épisodes de podcast
Scan quotidien automatique — 2026-06-24
Un cron tourne chaque nuit à 04h00 UTC pour scanner toutes les bibliothèques Audiobookshelf et détecter les nouveaux contenus ou les renommages de dossiers.
Script
/home/debian/abs_scan.sh — log : /var/log/abs_scan.log
0 4 * * * bash /home/debian/abs_scan.sh
Fonctionnement
- Authentification via
POST /loginpour obtenir un token JWT frais - Récupération de toutes les bibliothèques via
GET /api/libraries - Déclenchement d'un scan pour chaque bibliothèque via
POST /api/libraries/{id}/scan
Bibliothèques scannées : 36 (audiobooks + podcasts). Durée estimée : quelques minutes.
Exemple de log :
2026-06-24 04:00 SCAN OK 36/36 libs
REX — 2026-06-24 : audiobook illisible après renommage de dossier
Contexte
Audiobookshelf ne pouvait plus lire Les routes de la soie (Peter Frankopan). Erreur dans les logs :
Error: ENOENT: no such file or directory, stat '/audiobooks/Histoire/2 - Moyen Age/Peter Frankopan - Les routes de la soie/27_CH_08_LA_ROUTE_DU_CIEL.mp3'
Cause
Le dossier avait été renommé sur kDrive/NAS de Peter Frankopan - Les routes de la soie en Peter Frankopan-les routes de la soie (tiret sans espaces, minuscule). Audiobookshelf conservait l'ancien chemin dans sa base.
Solution
Le scan quotidien abs_scan.sh détecte ce type de désynchronisation et met à jour les chemins. Pour forcer immédiatement : lancer un scan manuel depuis l'interface Audiobookshelf ou exécuter bash /home/debian/abs_scan.sh.
05_BentoPDF
bentopdf
Unprivileged NGINX Dockerfiles
| Image | bentopdfteam/bentopdf-simple:latest |
|---|---|
| Version | 1.28.0-alpine-slim |
| Etat | Up 9 hours |
| Compose project | bentopdf |
| Reseau | bentopdf_default |
| URL | https://bento.juxjux.ovh |
| Source | https://github.com/alam00000/bentopdf |
Ports
| Hote | Container | IP |
|---|---|---|
| 8089 | 8080/tcp | 0.0.0.0 |
| 8089 | 8080/tcp | :: |
Integration Claude Code — API directe
| Statut MCP | Pas de MCP — API directe possible |
|---|---|
| Note technique | API REST interne, pas de MCP configuré. Accessible via PowerShell/Python httpx. |
Ce que nous pouvons faire ensemble
- Manipulation de PDF via l'API REST (fusion, découpage, conversion)
- Automatisation de traitements PDF dans des scripts Claude Code
06_Cadvisor
cadvisor
| Image | gcr.io/cadvisor/cadvisor:latest |
|---|---|
| Etat | Up 9 hours (healthy) |
| Compose project | gemini_grafana |
| Reseau | gemini_grafana_monitor_net |
Volumes
| Source (hote) | Destination | Type | Mode |
|---|---|---|---|
/var/run | /var/run | bind | rw |
/ | /root | bind | ro |
/sys | /sys | bind | ro |
/var/lib/docker | /var/lib/docker | bind | ro |
Integration Claude Code — API directe
| Statut MCP | Pas de MCP — API directe possible |
|---|---|
| Note technique | Endpoint Prometheus /metrics exposé à Prometheus (port 8080). Pas de MCP. Données lisibles via Prometheus MCP ou requêtes PromQL directes. |
Ce que nous pouvons faire ensemble
- Métriques CPU/RAM/réseau/disque par container (via Prometheus)
- Surveillance des performances en temps réel de chaque service
- Détection de containers consommant trop de ressources
07_Calibre-web
calibre-web-eyrolles
[Calibre-web](https://github.com/janeczku/calibre-web) is a web app providing a clean interface for browsing, reading and downloading eBooks using an existing Calibre database. It is also possible to integrate google drive and edit metadata and your calibre library through the app itself. This software is a fork of library and licensed under the GPL v3 License.
| Image | lscr.io/linuxserver/calibre-web:latest |
|---|---|
| Version | 0.6.26-ls383 |
| Etat | Up 9 hours (healthy) |
| Compose project | calibreweb_automated |
| Reseau | calibre_network |
| Source | https://github.com/linuxserver/docker-calibre-web |
Ports
| Hote | Container | IP |
|---|---|---|
| 8214 | 8083/tcp | 0.0.0.0 |
| 8214 | 8083/tcp | :: |
Volumes
| Source (hote) | Destination | Type | Mode |
|---|---|---|---|
/home/debian/livres/Eyrolles | /books | bind | rw |
/home/debian/docker/calibre-web-automated/config | /config | bind | rw |
Integration Claude Code — API directe
| Statut MCP | Pas de MCP — API directe possible |
|---|---|
| Note technique | Interface OPDS disponible pour parcourir la bibliothèque. API REST limitée. Pas de MCP configuré. |
Ce que nous pouvons faire ensemble
- Parcourir la bibliothèque Eyrolles via le catalogue OPDS
- Potentielle automatisation d'ajout/export de livres via l'API
08_Dozzle
dozzle
Realtime log viewer for containers. Supports Docker, Swarm and K8s.
| Image | amir20/dozzle:latest |
|---|---|
| Version | v8.14.9 |
| Etat | Up 9 hours |
| Compose project | dozzle |
| Reseau | nginx_npm-network |
| URL | https://dozzle.juxjux.ovh |
| Source | https://github.com/amir20/dozzle |
Ports
| Hote | Container | IP |
|---|---|---|
| 9091 | 8080/tcp | 0.0.0.0 |
| 9091 | 8080/tcp | :: |
Volumes
| Source (hote) | Destination | Type | Mode |
|---|---|---|---|
/var/run/docker.sock | /var/run/docker.sock | bind | rw |
Integration Claude Code — API directe
| Statut MCP | Pas de MCP — API directe possible |
|---|---|
| Note technique | Interface de visualisation de logs uniquement. Pas d'API publique exploitable. Les logs sont mieux accessibles via mcp__portainer__get_container_logs. |
Ce que nous pouvons faire ensemble
- Logs containers accessibles en alternative via le MCP Portainer
09_FileBrowser
File-Browser
| Image | filebrowser/filebrowser:latest |
|---|---|
| Version | 2.63.3 |
| Etat | Up 9 hours (healthy) |
| Compose project | filebrowser |
| Reseau | filebrowser_default |
| URL | https://files.juxjux.ovh |
| Source | https://github.com/filebrowser/filebrowser |
Ports
| Hote | Container | IP |
|---|---|---|
| 8147 | 80/tcp | 0.0.0.0 |
| 8147 | 80/tcp | :: |
Volumes
| Source (hote) | Destination | Type | Mode |
|---|---|---|---|
/home/debian/docker/filebrowser/database | /database | bind | rw |
/home/debian | /srv | bind | rw |
/home/debian/docker/filebrowser/config | /config | bind | rw |
Integration Claude Code — MCP
| Statut MCP | MCP actif |
|---|---|
| Outils (prefix) | mcp__filebrowser__ |
| Configuration | Script Python : C:\Users\eliob\.claude\mcp_filebrowser.py | Auth : JWT via POST /api/login (admin) |
Outils disponibles
list_filesread_text_fileupload_text_fileget_file_infosearch_filescopy_filemove_or_renamecreate_directorydelete_path
Ce que nous pouvons faire ensemble
10_FreshRSS
freshrss
A free, self-hostable news aggregator…
| Image | freshrss/freshrss:latest |
|---|---|
| Version | 1.28.1 |
| Etat | Up 26 minutes |
| Compose project | freshrss |
| Reseau | freshrss_default |
| URL | https://freshrss.juxjux.ovh |
| Source | https://github.com/FreshRSS/FreshRSS |
Ports
| Hote | Container | IP |
|---|---|---|
| 8081 | 80/tcp | 0.0.0.0 |
| 8081 | 80/tcp | :: |
Volumes
| Source (hote) | Destination | Type | Mode |
|---|---|---|---|
/home/debian/docker/freshrss/data | /var/www/FreshRSS/data | bind | rw |
Integration Claude Code — MCP
| Statut MCP | MCP actif |
|---|---|
| Outils (prefix) | mcp__freshrss__ |
| Configuration | Script Python : C:\Users\eliob\.claude\mcp_freshrss.py | Auth : GReader API avec mot de passe API dédié (≠ mot de passe web) |
Outils disponibles
get_feedsget_categoriesget_articlesget_unread_countget_starred_articlesmark_as_readmark_feed_as_readstar_articlesearch_articlesadd_feeddelete_feed
Ce que nous pouvons faire ensemble
- Lire les derniers articles de tous les flux RSS
- Rechercher des articles par mots-clés dans toute la veille
- Marquer des articles comme lus ou les étoiler
- Ajouter ou supprimer des flux
- Faire une synthèse de veille thématique à partir des non-lus
11_Gitea
gitea
Git with a cup of tea! Painless self-hosted all-in-one software development service, including Git hosting, code review, team collaboration, package registry and CI/CD
| Image | gitea/gitea:latest |
|---|---|
| Version | 1.25.4 |
| Etat | Up 9 hours (healthy) |
| Compose project | gitea |
| Reseau | gitea_default |
| URL | https://gitea.juxjux.ovh |
| Source | https://github.com/go-gitea/gitea |
Ports
| Hote | Container | IP |
|---|---|---|
| 2222 | 2222/tcp | 0.0.0.0 |
| 2222 | 2222/tcp | :: |
| 3005 | 3000/tcp | 0.0.0.0 |
| 3005 | 3000/tcp | :: |
Volumes
| Source (hote) | Destination | Type | Mode |
|---|---|---|---|
/var/lib/gitea_data | /data | bind | rw |
/etc/localtime | /etc/localtime | bind | ro |
/etc/timezone | /etc/timezone | bind | ro |
Integration Claude Code — API directe
| Statut MCP | Pas de MCP — API directe possible |
|---|---|
| Note technique | API REST Gitea complète disponible sur /api/v1. Auth : token Bearer ou Basic Auth. Pas de MCP configuré — appels directs via PowerShell/Python. |
Ce que nous pouvons faire ensemble
- Lister repositories, branches, commits via l'API REST
- Lire/écrire des fichiers dans les repos (contenu base64)
- Gérer issues, pull requests, tags et releases
- Automatiser des workflows de versionning depuis Claude Code
12_Grafana
grafana
| Image | grafana/grafana:latest |
| Etat | Up 5 days (healthy) |
| Compose project | gemini_grafana (stack ID 63) |
| Réseau | gemini_grafana_monitor_net |
| URL | https://grafana.juxjux.ovh |
| Source | https://github.com/grafana/grafana |
Ports
| Hote | Container | IP |
|---|---|---|
| 3000 | 3000/tcp | 0.0.0.0 |
| 3000 | 3000/tcp | :: |
Volumes
| Source (hote) | Destination | Type | Mode |
|---|---|---|---|
/opt/monitoring/grafana_data |
/var/lib/grafana |
bind | rw |
Intégration Claude Code — API directe
| Statut MCP | Pas de MCP — API directe possible |
| Note technique | API REST Grafana sur /api. Auth : clé API ou Basic Admin. Pas de MCP configuré — appels directs possibles. |
Ce que nous pouvons faire ensemble
- Lister les dashboards et leur état
- Interroger des datasources Prometheus via l'API (PromQL)
- Créer ou modifier des annotations sur les graphiques
- Exporter des dashboards en JSON pour sauvegarde/versioning
Compte rendu — 2026-06-11
Vérification via Portainer MCP (endpoint 3) + Prometheus PromQL (localhost:9090).
Métriques VPS globales
| Métrique | Valeur | |
|---|---|---|
| RAM | 8.4 / 11.41 GB | 73.6% |
| Swap | 3.99 / 4.0 GB | quasi plein |
| CPU | 5.2% | — |
Stack gemini_grafana — 4 containers, tous running (5 jours)
| Container | Image | Etat | Healthcheck | Port exposé |
|---|---|---|---|---|
| grafana | grafana/grafana:latest | running | healthy | 3000 |
| prometheus | prom/prometheus:latest | running | — | 9090 |
| node-exporter | prom/node-exporter:latest | running | — | 9100 |
| cadvisor | gcr.io/cadvisor/cadvisor:latest | running | healthy | 8080 (interne) |
Notes
- Stack ID Portainer : 63 — compose sur
/data/compose/63/docker-compose.yml - Config Prometheus :
/opt/monitoring/prometheus.yml| Data :/opt/monitoring/prometheus_data --web.enable-lifecycleactif sur Prometheus (reload API disponible sur:9090/-/reload)- cadvisor port 8080 non exposé publiquement (aucun mapping IP externe)
- grafana.juxjux.ovh : DNS non résolu depuis l'extérieur — pas de vhost nginx configuré, accès direct via port 3000
- Ports 3000, 9090, 9100 exposés sur
0.0.0.0— à vérifier dans ufw
13_Immich
Immich-SERVER
High performance self-hosted photo and video management solution.
| Image | ghcr.io/immich-app/immich-server:release |
|---|---|
| Version | v2.7.5 |
| Etat | Up (healthy) |
| Compose project | immich |
| Reseau | immich_immich-network |
| URL | https://immich.juxjux.ovh |
| Source | https://github.com/immich-app/immich |
Ports
| Hote | Container | IP |
|---|---|---|
| 8212 | 2283/tcp | 0.0.0.0 |
| 8212 | 2283/tcp | :: |
Volumes
| Source (hote) | Destination | Type | Mode |
|---|---|---|---|
/home/debian/docker/immich/upload | /data | bind | rw |
/etc/localtime | /etc/localtime | bind | ro |
/home/debian/docker/immich/upload/encoded-video | /mnt/media/encoded-video | bind | rw |
/home/debian/photo | /mnt/media/photo | bind | ro,shared |
Immich-MICROSERVICES
High performance self-hosted photo and video management solution.
| Image | ghcr.io/immich-app/immich-server:release |
|---|---|
| Version | v2.7.5 |
| Etat | Up (healthy) |
| Compose project | immich |
| Reseau | immich_immich-network |
| URL | https://immich.juxjux.ovh |
| Source | https://github.com/immich-app/immich |
Volumes
| Source (hote) | Destination | Type | Mode |
|---|---|---|---|
/home/debian/docker/immich/upload | /data | bind | rw |
/etc/localtime | /etc/localtime | bind | ro |
/home/debian/docker/immich/upload/encoded-video | /mnt/media/encoded-video | bind | rw |
/home/debian/photo | /mnt/media/photo | bind | ro,shared |
Immich-LEARNING
High performance self-hosted photo and video management solution.
| Image | ghcr.io/immich-app/immich-machine-learning:release |
|---|---|
| Version | v2.7.5 |
| Etat | Up (healthy) |
| Compose project | immich |
| Reseau | immich_immich-network |
| URL | https://immich.juxjux.ovh |
| Source | https://github.com/immich-app/immich |
Volumes
| Source (hote) | Destination | Type | Mode |
|---|---|---|---|
/home/debian/docker/immich/cache | /cache | bind | rw |
Immich-REDIS
| Image | redis:6.2-alpine |
|---|---|
| Etat | Up (healthy) |
| Compose project | immich |
| Reseau | immich_immich-network |
| URL | https://immich.juxjux.ovh |
Volumes
| Source (hote) | Destination | Type | Mode |
|---|---|---|---|
/data | volume | rw |
Immich-DB
Base images for Immich containers
| Image | ghcr.io/immich-app/postgres:16-vectorchord0.3.0-pgvectors0.2.0 |
|---|---|
| Version | 16-vectorchord0.3.0-pgvector0.8.1-pgvectors0.2.0 |
| Etat | Up (healthy) |
| Compose project | immich |
| Reseau | immich_immich-network |
| URL | https://immich.juxjux.ovh |
| Source | https://github.com/immich-app/base-images |
Volumes
| Source (hote) | Destination | Type | Mode |
|---|---|---|---|
/home/debian/docker/immich/db | /var/lib/postgresql/data | bind | rw |
Integration Claude Code — MCP
| Statut MCP | MCP actif |
|---|---|
| Outils (prefix) | mcp__immich__ |
| Configuration | Script Python : C:\Users\eliob\.claude\mcp_immich.py | Auth : JWT via POST /api/auth/login |
Outils disponibles
get_assetsget_assetsearch_assetsupdate_assetget_albumsget_albumcreate_albumget_peopleget_person_assetsget_memoriesget_statisticsget_my_userget_server_info
Ce que nous pouvons faire ensemble
- Rechercher des photos par date, lieu, contenu ou personne reconnue
- Parcourir les albums et les souvenirs générés automatiquement
- Consulter les statistiques de la photothèque (nb photos, vidéos, taille)
- Créer un album et y regrouper des assets
- Mettre à jour les métadonnées d'un asset (description, date, lieu)
Sauvegarde de la base de données
Sauvegarde automatique quotidienne de la base PostgreSQL Immich-DB vers kDrive Infomaniak. Mise en place le 2026-06-01.
Paramètres
| Script | /opt/backups/vps_backup.sh |
|---|---|
| Cron | Tous les jours à 2h du matin (0 2 * * *) |
| Container DB | Immich-DB (PostgreSQL 16) |
| Commande | pg_dump -U postgres |
| Taille base (disque) | ~7.5 Mo (métadonnées uniquement — photos sur volume séparé) |
| Format archive | .7z (compression niveau 5) |
| Destination | kDrive Infomaniak — TOOJUX/jux_vps/immich (dossier ID 1427919) |
| Rétention | 7 jours glissants |
| Nommage fichier | immich_db_YYYY-MM-DD.7z |
Note importante
Cette sauvegarde couvre uniquement les métadonnées (albums, faces, tags, utilisateurs). Les fichiers photos/vidéos sont stockés dans /home/debian/docker/immich/upload et /home/debian/photo — ils ne sont pas inclus dans ce backup.
REX — 2026-06-21 — FUSE cassé après restart rclone-photo
Symptôme
Immich connecté mais aucune photo visible. Logs Immich-SERVER :
WARN [Microservices:LibraryService] Skipping invalid import path: /mnt/media/photo. Reason: Error: ENOTCONN: socket is not connected, stat '/mnt/media/photo'
Cause
Le service rclone-photo.service a redémarré le 2026-06-18 (suite à l'incident sécurité du 2026-06-09 — fix --rc-addr 127.0.0.1). Les containers Immich-SERVER et Immich-MICROSERVICES, démarrés avant ce restart, conservent un file descriptor FUSE invalide. La propagation :shared aide pour les nouveaux montages mais ne restaure pas un fd FUSE mort.
Fix immédiat
docker restart Immich-SERVER Immich-MICROSERVICES
# puis déclencher un scan de bibliothèque :
curl -s -X POST "https://immich.juxjux.ovh/api/libraries/89bfcdc1-1604-47a1-90a3-975d2f6c4639/scan" \
-H "Authorization: Bearer TOKEN"
# TOKEN obtenu via POST /api/auth/login (bertrand.dadone@gmail.com / 27101809)
Fix structurel — ExecStartPost dans rclone-photo.service (2026-06-21)
Ajout d'un ExecStartPost dans /etc/systemd/system/rclone-photo.service : à chaque redémarrage de rclone-photo, les containers Immich sont automatiquement relancés si et seulement s'ils tournent déjà (pas de blocage au boot).
ExecStartPost=/bin/bash -c 'sleep 3; docker ps --filter name=Immich-SERVER --filter status=running -q | grep -q . && docker restart Immich-SERVER Immich-MICROSERVICES || true'
Rechargement : sudo systemctl daemon-reload (pas de restart du service nécessaire — prendra effet au prochain redémarrage de rclone-photo).
Library ID Immich
89bfcdc1-1604-47a1-90a3-975d2f6c4639
Inventaire par Claude le 251001
14_Jellyfin
jellyfin
The Free Software Media System
| Image | jellyfin/jellyfin:latest |
|---|---|
| Version | 10.10.7 |
| Etat | Up 9 hours (healthy) |
| Compose project | jellyfin |
| Reseau | host |
| URL | https://jellyfin.juxjux.ovh |
| Source | https://github.com/jellyfin/jellyfin-packaging |
Volumes
| Source (hote) | Destination | Type | Mode |
|---|---|---|---|
/mnt/nas_videos/movies | /data/movies | bind | rw |
/mnt/nas_videos/palettes | /data/palettes | bind | rw |
/home/debian/jellyfin/config | /config | bind | rw |
/mnt/nas_videos/cinema_europe | /data/cinema_europe | bind | rw |
/mnt/nas_videos/cinema_UK | /data/cinema_uk | bind | rw |
/mnt/nas_videos/spectacles | /data/spectacles | bind | rw |
| /cache | volume | rw |
/mnt/nas_videos/animes | /data/animes | bind | rw |
/mnt/nas_videos/cinema_asie | /data/cinema_asie | bind | rw |
/mnt/nas_videos/cinema_realisateurs | /data/cinema_realisateurs | bind | rw |
/mnt/nas_videos/fantastique_et_SF | /data/fantastique_et_SF | bind | rw |
/mnt/nas_videos/historiques | /data/historiques | bind | rw |
/mnt/nas_videos/series | /data/series | bind | rw |
/mnt/nas_videos/cinema_italie | /data/cinema_italie | bind | rw |
/mnt/nas_videos/culture_cuisine | /data/culture_cuisine | bind | rw |
/mnt/nas_videos/documentaires | /data/documentaires | bind | rw |
Integration Claude Code — MCP
| Statut MCP | MCP actif |
|---|---|
| Outils (prefix) | mcp__jellyfin__ |
| Configuration | Script Python : C:\Users\eliob\.claude\mcp_jellyfin.py | Auth : JWT MediaBrowser Token via POST /Users/AuthenticateByName |
Outils disponibles
get_librariesget_itemsget_itemget_recently_addedget_resume_itemsget_sessionsget_usersget_server_infoscan_librarysearch_items
Ce que nous pouvons faire ensemble
- Parcourir films, séries et musiques de la médiathèque
- Voir les ajouts récents et les éléments en cours de lecture
- Surveiller les sessions actives (qui lit quoi en ce moment)
- Déclencher un scan de bibliothèque après ajout de contenu
- Rechercher un titre dans toute la médiathèque
15_Joplin
joplin_to_obsidian
| Image | joplin_to_obsidian-joplin_to_obsidian |
|---|---|
| Etat | Up 9 hours |
| Compose project | joplin_to_obsidian |
| Reseau | joplin_joplin_network |
| URL | https://joplin.juxjux.ovh |
Volumes
| Source (hote) | Destination | Type | Mode |
|---|---|---|---|
/home/debian/Documents/Joplin_Obsidian | /home/debian/Documents/Joplin_Obsidian | bind | rw |
joplin-nginx
| Image | nginx:alpine |
|---|---|
| Etat | Up 9 hours |
| Compose project | joplin |
| Reseau | joplin_joplin_network |
| URL | https://joplin.juxjux.ovh |
Ports
| Hote | Container | IP |
|---|---|---|
| 22301 | 80/tcp | 0.0.0.0 |
| 22301 | 80/tcp | :: |
joplin
Docker image for Joplin Server
| Image | joplin/server:latest |
|---|---|
| Version | 3.4.3 |
| Etat | Up 9 hours |
| Compose project | joplin |
| Reseau | joplin_joplin_network |
| URL | https://joplin.juxjux.ovh |
| Source | https://github.com/laurent22/joplin.git |
Ports
| Hote | Container | IP |
|---|---|---|
| 22300 | 22300/tcp | 0.0.0.0 |
| 22300 | 22300/tcp | :: |
Volumes
| Source (hote) | Destination | Type | Mode |
|---|---|---|---|
/home/debian/joplin-data | /home/joplin/.config/joplin | bind | rw |
joplin-db
| Image | postgres:15-alpine |
|---|---|
| Etat | Up 9 hours |
| Compose project | joplin |
| Reseau | joplin_joplin_network |
| URL | https://joplin.juxjux.ovh |
Volumes
| Source (hote) | Destination | Type | Mode |
|---|---|---|---|
/home/debian/joplin-db-data | /var/lib/postgresql/data | bind | rw |
Integration Claude Code — API directe
| Statut MCP | Pas de MCP — API directe possible |
|---|---|
| Note technique | Le container Joplin est un serveur de synchronisation (sync server), pas un serveur de notes interrogeable. Pas d'API de lecture du contenu. Le container joplin_to_obsidian est un script de migration ponctuelle vers Obsidian. |
Ce que nous pouvons faire ensemble
- Synchronisation des notes entre appareils (via le client Joplin)
- Migration Joplin → Obsidian via le script joplin_to_obsidian (ponctuel)
Sauvegarde de la base de données
Sauvegarde automatique quotidienne de la base PostgreSQL joplin-db vers kDrive Infomaniak. Mise en place le 2026-06-01.
Paramètres
| Script | /opt/backups/vps_backup.sh |
|---|---|
| Cron | Tous les jours à 2h du matin (0 2 * * *) |
| Container DB | joplin-db (PostgreSQL 15) |
| Commande | pg_dump -U joplin -d joplin |
| Taille base (disque) | ~1.4 Go (notes + pièces jointes stockées en BLOB) |
| Format archive | .7z (compression niveau 5) |
| Destination | kDrive Infomaniak — TOOJUX/jux_vps/joplin (dossier ID 1427920) |
| Rétention | 7 jours glissants |
| Nommage fichier | joplin_db_YYYY-MM-DD.7z |
Note
La base est volumineuse (~1.4 Go) car Joplin stocke toutes les pièces jointes en BLOB dans PostgreSQL. L'archive compressée pèse ~500 Mo à 1 Go. Quota kDrive consommé : ~3.5 à 7 Go pour 7 jours.
Observatoire Joplin-Compression
Mis ? jour le 14/06/2026 12:50 ? dernier run compression : 2026-06-14T10:47
Bilan global
| Ressources totales (actuelles) | 736 fichiers |
|---|---|
| Poids total actuel | 119.7 Mo |
| Ressources compress?es | 424 |
| Poids avant compression | 451.5 Mo |
| ?conomie r?alis?e | 356.3 Mo (-78.9%) |
| Ignor?es (gain insuffisant) | 212 |
| Erreurs | 0 |
Top 15 ressources les plus lourdes (?tat actuel)
| # | ID | Format | Taille actuelle | Gain compression |
|---|---|---|---|---|
| 1 | vVO2ePdMvtty3sXZy5nY6M | ? | 3146 KB | |
| 2 | 0xh87pWrRt82z0DbO9n3yQ | ZIP | 2250 KB | -81% |
| 3 | VasIoF2e9EGuNQt38aOFMx | JPEG | 1633 KB | -66% |
| 4 | TzWK21r4n0yvbEtJh02DGB | JPEG | 1529 KB | -63% |
| 5 | M0C32hKC2hMqPAxpRGiVgp | JPEG | 937 KB | -87% |
| 6 | Hn6z6lvvbJzRsX0KGM8FNW | JPEG | 928 KB | -53% |
| 7 | 7EyAL9NNysJzWke6NT4ttJ | JPEG | 803 KB | -76% |
| 8 | bz9Twmb2F5lj0mPIQi48IB | JPEG | 798 KB | -81% |
| 9 | UbAqQY3cEbH62vioIHU6Pj | JPEG | 776 KB | -87% |
| 10 | SrJi1UyeNGf8OhaRsaOCGq | JPEG | 745 KB | -79% |
| 11 | 87mV49tXupZcpt2wplcGjU | JPEG | 685 KB | -59% |
| 12 | JsJFO6dIzqMKLA7clqW8nG | JPEG | 683 KB | -66% |
| 13 | VSyNmO0uN1fNNeqN6XZucO | JPEG | 674 KB | -19% |
| 14 | hExoJEEWT2tHz1demE5Nhm | JPEG | 674 KB | -84% |
| 15 | slTzAxAQ4xi0pMvzsLIDez | ? | 670 KB |
Observatoire Joplin-Compression
Mis ? jour le 15/06/2026 03:00 ? dernier run compression : 2026-06-15T03:00
Bilan global
| Ressources totales (actuelles) | 736 fichiers |
|---|---|
| Poids total actuel | 119.9 Mo |
| Ressources compress?es | 425 |
| Poids avant compression | 452.0 Mo |
| ?conomie r?alis?e | 356.4 Mo (-78.8%) |
| Ignor?es (gain insuffisant) | 212 |
| Erreurs | 0 |
Top 15 ressources les plus lourdes (?tat actuel)
| # | ID | Format | Taille actuelle | Gain compression |
|---|---|---|---|---|
| 1 | vVO2ePdMvtty3sXZy5nY6M | ? | 3146 KB | |
| 2 | 0xh87pWrRt82z0DbO9n3yQ | ZIP | 2250 KB | -81% |
| 3 | VasIoF2e9EGuNQt38aOFMx | JPEG | 1633 KB | -66% |
| 4 | TzWK21r4n0yvbEtJh02DGB | JPEG | 1529 KB | -63% |
| 5 | M0C32hKC2hMqPAxpRGiVgp | JPEG | 937 KB | -87% |
| 6 | Hn6z6lvvbJzRsX0KGM8FNW | JPEG | 928 KB | -53% |
| 7 | 7EyAL9NNysJzWke6NT4ttJ | JPEG | 803 KB | -76% |
| 8 | bz9Twmb2F5lj0mPIQi48IB | JPEG | 798 KB | -81% |
| 9 | UbAqQY3cEbH62vioIHU6Pj | JPEG | 776 KB | -87% |
| 10 | SrJi1UyeNGf8OhaRsaOCGq | JPEG | 745 KB | -79% |
| 11 | 87mV49tXupZcpt2wplcGjU | JPEG | 685 KB | -59% |
| 12 | JsJFO6dIzqMKLA7clqW8nG | JPEG | 683 KB | -66% |
| 13 | VSyNmO0uN1fNNeqN6XZucO | JPEG | 674 KB | -19% |
| 14 | hExoJEEWT2tHz1demE5Nhm | JPEG | 674 KB | -84% |
| 15 | slTzAxAQ4xi0pMvzsLIDez | ? | 670 KB |
Observatoire Joplin-Compression
Mis ? jour le 16/06/2026 03:00 ? dernier run compression : 2026-06-16T03:00
Bilan global
| Ressources totales (actuelles) | 736 fichiers |
|---|---|
| Poids total actuel | 119.9 Mo |
| Ressources compress?es | 425 |
| Poids avant compression | 452.0 Mo |
| ?conomie r?alis?e | 356.4 Mo (-78.8%) |
| Ignor?es (gain insuffisant) | 212 |
| Erreurs | 0 |
Top 15 ressources les plus lourdes (?tat actuel)
| # | ID | Format | Taille actuelle | Gain compression |
|---|---|---|---|---|
| 1 | vVO2ePdMvtty3sXZy5nY6M | ? | 3146 KB | |
| 2 | 0xh87pWrRt82z0DbO9n3yQ | ZIP | 2250 KB | -81% |
| 3 | VasIoF2e9EGuNQt38aOFMx | JPEG | 1633 KB | -66% |
| 4 | TzWK21r4n0yvbEtJh02DGB | JPEG | 1529 KB | -63% |
| 5 | M0C32hKC2hMqPAxpRGiVgp | JPEG | 937 KB | -87% |
| 6 | Hn6z6lvvbJzRsX0KGM8FNW | JPEG | 928 KB | -53% |
| 7 | 7EyAL9NNysJzWke6NT4ttJ | JPEG | 803 KB | -76% |
| 8 | bz9Twmb2F5lj0mPIQi48IB | JPEG | 798 KB | -81% |
| 9 | UbAqQY3cEbH62vioIHU6Pj | JPEG | 776 KB | -87% |
| 10 | SrJi1UyeNGf8OhaRsaOCGq | JPEG | 745 KB | -79% |
| 11 | 87mV49tXupZcpt2wplcGjU | JPEG | 685 KB | -59% |
| 12 | JsJFO6dIzqMKLA7clqW8nG | JPEG | 683 KB | -66% |
| 13 | VSyNmO0uN1fNNeqN6XZucO | JPEG | 674 KB | -19% |
| 14 | hExoJEEWT2tHz1demE5Nhm | JPEG | 674 KB | -84% |
| 15 | slTzAxAQ4xi0pMvzsLIDez | ? | 670 KB |
16_Kavita
Kavita
Kavita is a fast, feature rich, cross platform reading server. Built with the goal of being a full solution for all your reading needs. Setup your own server and share your reading collection with your friends and family.
| Image | jvmilazz0/kavita:latest |
| Version | latest |
| Etat | Up (healthy) |
| Compose project | kavita |
| Réseau | kavita_default |
| URL | https://kavita.juxjux.ovh |
| Source | https://github.com/Kareadita/Kavita |
Ports
| Hote | Container | IP |
|---|---|---|
| 5471 | 5000/tcp | 0.0.0.0 |
Volumes
| Source (hote) | Destination | Type | Mode |
|---|---|---|---|
/home/debian/docker/kavita/config |
/kavita/config |
bind | rw |
/home/debian/livres |
/manga |
bind | rw |
Integration Claude Code — MCP
| Statut MCP | MCP actif |
| Outils (prefix) | mcp__kavita__ |
| Configuration | Script Python : C:\Users\eliob\.claude\mcp_kavita.py | Auth : JWT via POST /api/Account/login |
Outils opérationnels (confirmés 2026-06-25)
get_libraries— liste les 53 bibliothèquesget_series— liste les séries (filtre library_id non fonctionnel : retourne toutes les bibliothèques)get_series_detailget_series_metadata— retourne genres, auteurs, éditeur, résumé, annéeget_series_volumesget_recently_addedget_on_deck— séries en cours de lectureget_server_statssearch— recherche full-text sur noms de séries, genres, fichiers, chapitresget_collections— corrigé 2026-06-25get_reading_lists— corrigé 2026-06-25get_want_to_read— corrigé 2026-06-25add_to_want_to_readremove_from_want_to_readget_user_stats— corrigé 2026-06-25get_reading_list
Ce que nous pouvons faire ensemble
- Parcourir la bibliothèque par série, volume ou bibliothèque thématique
- Rechercher un titre, auteur ou genre
- Consulter les séries récemment ajoutées ou en cours de lecture
- Gérer la liste "À lire" (ajout/suppression)
- Consulter les collections et listes de lecture
- Appeler l'API directement via PowerShell pour filtrer par genre (
/api/Series/all-v2)
REX — 2026-06-25
Statistiques bibliothèque
| Stat | Valeur |
|---|---|
| Bibliothèques | 53 (toutes de type Book/epub+PDF) |
| Séries | 2 976 |
| Fichiers | 5 519 |
| Volumes | 1 173 |
| Taille totale | ~79 Go |
| Auteurs/contributeurs indexés | 3 475 |
| Genres indexés | 6 990 |
| Tags | 0 |
Étiquettes Calibre → genres Kavita
Les étiquettes appliquées via Calibre sont visibles dans Kavita sous le champ genres, pas tags (qui reste toujours vide, totalTags: 0).
Mécanisme : Calibre écrit ses étiquettes dans <dc:subject> du fichier epub lors du writeback → Kavita lit ce champ et le mappe en genres.
Exemple confirmé — "Il faut s'adapter" (Barbara Stiegler, lib. Actualités, ID série 4210) :
- genres :
Actualités,Philosophie,Politique,2020-2025
Conditions pour que ça fonctionne :
- Le fichier epub doit avoir été re-sauvegardé depuis Calibre après ajout des étiquettes (Préférences > Sauvegarde des métadonnées → writeback activé)
- La bibliothèque Kavita doit avoir
enableMetadata: true(c'est le cas pour Actualités) - Les PDFs ne portent généralement pas les métadonnées Calibre → genres vides
La bibliothèque Actualités (ID 63) est entièrement étiquetée et correctement indexée.
Lecture du contenu
Le MCP ne permet pas de lire le contenu des livres — uniquement les métadonnées. Kavita expose des endpoints de lecture (/api/Reader/image, /api/Reader/epub-file) mais non implémentés dans le MCP. Pour les epub, la lecture via appel API direct + parsing HTML serait techniquement faisable au cas par cas.
Corrections endpoints MCP (2026-06-25)
4 outils retournaient 404 suite à des changements d'API dans la version Kavita en production. Corrections appliquées dans mcp_kavita.py :
| Outil | Ancien endpoint (404) | Nouveau endpoint (200) |
|---|---|---|
get_collections |
GET /api/Collection/list |
GET /api/Collection |
get_reading_lists |
GET /api/ReadingList/lists?includePromoted=true |
POST /api/ReadingList/lists body {} |
get_want_to_read |
POST /api/Want-To-Read/get-list |
POST /api/Want-To-Read |
get_user_stats |
GET /api/Stats/user/0/read |
GET /api/Stats/user-stats?userId={id} |
Note : le userId est désormais extrait dynamiquement du payload de login (data["id"]) et stocké dans _user_id.
Limitations MCP identifiées
- Le paramètre
library_iddeget_seriesne filtre pas : retourne toutes les bibliothèques triées alphabétiquement - Pour filtrer par genre, utiliser l'API directe :
POST /api/Series/all-v2avec filtre JSON (hors MCP, via PowerShell)
Problème pipeline Calibre → Kavita — À résoudre
Constat (2026-06-25) : les fichiers enrichis par Calibre (avec étiquettes + métadonnées ISBN) ne remplacent pas les fichiers originaux dans le dossier Kavita. Kavita lit depuis le dossier source original (/manga = kDrive Sync_NAS-Maison/Foxy) qui contient les fichiers sans métadonnées.
Calibre, en mode par défaut, copie les fichiers dans sa propre arborescence et les enrichit là — les originaux restent intacts. Résultat : 98% des fichiers ont des métadonnées correctes dans Calibre, mais Kavita voit des genres vides.
Questions ouvertes à clarifier :
- Où est la bibliothèque Calibre (Windows, NAS Maison, autre) ?
- Le dossier source Kavita et le dossier d'import Calibre sont-ils le même, ou séparés ?
- Calibre est-il en mode copie (défaut) ou lien vers fichier original ?
Piste de solution : exporter les fichiers enrichis depuis la bibliothèque Calibre vers le dossier source Kavita (via "Enregistrer sur le disque" dans Calibre), en remplacement des originaux. Peut s'automatiser. À instruire.
17_Komga
komga
| Image | gotson/komga |
|---|---|
| Version | 24.10 |
| Etat | Up 9 hours |
| Compose project | komga |
| Reseau | komga_default |
| URL | https://komga.juxjux.ovh |
| Source | https://github.com/gotson/komga |
Ports
| Hote | Container | IP |
|---|---|---|
| 25600 | 25600/tcp | 0.0.0.0 |
| 25600 | 25600/tcp | :: |
Volumes
| Source (hote) | Destination | Type | Mode |
|---|---|---|---|
/home/debian/docker/komga/config | /config | bind | rw |
/home/debian/komga | /data | bind | rw |
/etc/timezone | /etc/timezone | bind | ro |
| /tmp | volume | rw |
Integration Claude Code — MCP
| Statut MCP | MCP actif |
|---|---|
| Outils (prefix) | mcp__komga__ |
| Configuration | Script Python : C:\Users\eliob\.claude\mcp_komga.py | Auth : Basic Auth (Base64 login:password) |
Outils disponibles
get_librariesget_seriesget_series_detailget_series_booksget_bookget_book_metadataget_booksget_latest_booksget_new_seriesget_updated_seriesget_on_deckget_read_listsget_read_listget_collectionsget_collectionsearchmark_series_readupdate_book_progressget_recently_added
Ce que nous pouvons faire ensemble
- Parcourir la bibliothèque comics/manga par série et tome
- Voir les dernières acquisitions et séries mises à jour
- Marquer une série comme lue ou mettre à jour la progression
- Gérer les listes de lecture et collections
- Rechercher dans toute la bibliothèque
18_Mealie
mealie
Mealie is a self hosted recipe manager and meal planner with a RestAPI backend and a reactive frontend application built in Vue for a pleasant user experience for the whole family. Easily add recipes into your database by providing the url and mealie will automatically import the relevant data or add a family recipe with the UI editor
| Image | ghcr.io/mealie-recipes/mealie:latest |
|---|---|
| Version | v3.16.0 |
| Etat | Up 9 hours (healthy) |
| Compose project | mealie2 |
| Reseau | mealie2_default |
| URL | https://mealie.juxjux.ovh |
| Source | https://github.com/mealie-recipes/mealie |
Ports
| Hote | Container | IP |
|---|---|---|
| 9925 | 9000/tcp | 0.0.0.0 |
| 9925 | 9000/tcp | :: |
Volumes
| Source (hote) | Destination | Type | Mode |
|---|---|---|---|
/home/debian/docker/mealie/backups | /app/backups | bind | rw |
/home/debian/docker/mealie/config | /app/config | bind | rw |
/home/debian/docker/mealie/data | /app/data | bind | rw |
Integration Claude Code — MCP
| Statut MCP | MCP actif |
|---|---|
| Outils (prefix) | mcp__mealie__ |
| Configuration | Script Python : C:\Users\eliob\.claude\mcp_mealie.py | Auth : OAuth2 Bearer Token via POST /api/auth/token |
Outils disponibles
get_recipesget_recipecreate_recipecreate_recipe_from_urldelete_recipeget_categoriesget_tagsget_cookbooksget_cookbookget_meal_planadd_meal_plan_entryget_shopping_listsget_shopping_listadd_shopping_item
Ce que nous pouvons faire ensemble
- Parcourir et rechercher des recettes par catégorie ou tag
- Importer automatiquement une recette depuis une URL
- Planifier les repas de la semaine
- Gérer les listes de courses (ajout d'ingrédients)
- Créer une recette depuis une description ou un texte fourni
Sauvegarde de la base de données
Sauvegarde automatique quotidienne de la base SQLite de Mealie vers kDrive Infomaniak. Mise en place le 2026-06-01.
Paramètres
| Script | /opt/backups/vps_backup.sh |
|---|---|
| Cron | Tous les jours à 2h du matin (0 2 * * *) |
| Type base | SQLite — /app/data/mealie.db (dans le container) |
| Méthode | docker cp mealie:/app/data/mealie.db |
| Taille base | ~2.9 Mo |
| Format archive | .7z (compression niveau 5) |
| Destination | kDrive Infomaniak — TOOJUX/jux_vps/mealie (dossier ID 1427921) |
| Rétention | 7 jours glissants |
| Nommage fichier | mealie_db_YYYY-MM-DD.7z |
19_Navidrome
navidrome-navidrome-1
🎧 Your Personal Streaming Service
| Image | deluan/navidrome:latest |
|---|---|
| Version | 0.61.2 |
| Etat | Up |
| Compose project | navidrome |
| Reseau | navidrome_default |
| URL | https://navidrome.juxjux.ovh |
| Source | https://github.com/navidrome/navidrome |
Ports
| Hote | Container | IP |
|---|---|---|
| 4533 | 4533/tcp | 0.0.0.0 |
Volumes
| Source (hote) | Destination | Type | Mode |
|---|---|---|---|
/home/debian/music |
/music |
bind | rw, :shared |
/home/debian/docker/navidrome/data |
/data |
bind | rw |
Integration Claude Code — MCP
| Statut MCP | MCP actif |
|---|---|
| Outils (prefix) | mcp__navidrome__ |
| Configuration | Script Python : C:\Users\eliob\.claude\mcp_navidrome.py | Auth : Subsonic API avec hachage MD5 (user + token + sel) |
Outils disponibles
pingget_artistsget_artistget_albumsget_albumget_songget_genresget_random_songsget_playlistsget_playlistcreate_playlistget_starredstarunstarsearchget_now_playing
Ce que nous pouvons faire ensemble
- Parcourir artistes, albums et pistes de la médiathèque musicale
- Rechercher un titre, artiste ou album
- Voir ce qui est en cours de lecture (now playing)
- Gérer les playlists (création, lecture)
- Étoiler/désigner des favoris
- Générer une sélection aléatoire par genre
Scans automatiques
Trois mécanismes automatiques assurent la fraîcheur de la bibliothèque :
| Cron | Script | Type | Rôle |
|---|---|---|---|
*/5 * * * * |
/home/debian/monitor-rclone.sh |
Watchdog | Détecte FUSE mort → restart service + restart container (recovery auto) |
30 4 * * * |
/home/debian/navidrome_scan.sh |
Quick scan | vfs/refresh + scan quotidien (MAJ des titres existants) |
0 3 * * 1 |
/home/debian/navidrome_fullscan.sh |
Full scan | vfs/refresh + restart container → full scan hebdomadaire (détecte nouveaux albums/artistes) |
Log commun : /var/log/navidrome_scan.log
Quick scan vs Full scan
Le quick scan (startScan via API Subsonic) ne traverse que les dossiers déjà connus de Navidrome — il ne détecte pas les nouveaux artistes ou albums ajoutés sur kDrive. Seul un full scan indexe les nouveaux dossiers.
Le full scan est déclenché automatiquement au démarrage du container. C'est pourquoi navidrome_fullscan.sh fait un restart container plutôt qu'un simple appel API.
Auth RC sur kdrive-music.service
Depuis rclone 1.74.3, vfs/refresh exige une authentification RC. Le service kdrive-music.service a été mis à jour le 2026-06-24 avec --rc-user=rcadmin --rc-pass=RcMusic2026!.
Commande de refresh manuel :
rclone rc --rc-addr 127.0.0.1:5576 --rc-user=rcadmin --rc-pass=RcMusic2026! vfs/refresh recursive=true
REX — 2026-06-24 : FUSE mort récurrent
Contexte
Le FUSE /music est mort en cours de journée. Symptôme Navidrome : stat /music: transport endpoint is not connected lors du scan.
Cause
Le service kdrive-music.service peut rester active (running) avec un FUSE mort — le process rclone est vivant mais la connexion noyau FUSE est cassée. Systemd ne détecte pas ce cas et ne redémarre pas le service.
Solution mise en place
Refactorisation de monitor-rclone.sh pour utiliser systemctl restart (au lieu d'un rclone mount direct) et redémarrer les containers Docker après remontage. Le watchdog tourne toutes les 5 minutes — la panne est détectée et corrigée automatiquement sans intervention.
Procédure manuelle si besoin
sudo systemctl restart kdrive-music.service
ls /home/debian/music | head -5
sudo docker restart navidrome-navidrome-1
Puis force-fermer Symfonium et relancer — le token de session Navidrome est invalidé après le restart du container.
REX — 2026-06-24 : nouveaux albums non détectés
Contexte
Les Négresses Vertes (et d'autres albums récemment ajoutés sur kDrive) n'apparaissaient pas dans Navidrome malgré le cron quotidien.
Cause
Double problème :
- Cache VFS 72h :
--dir-cache-time 72hsurkdrive-music.service— les nouveaux dossiers kDrive ne sont pas visibles dans le mount avant expiration ouvfs/refresh. - Quick scan insuffisant : le scan quotidien (
startScanAPI) est un quick scan qui ne traverse que les dossiers déjà connus. Il ne détecte pas de nouveaux artistes.
Solution immédiate
rclone rc --rc-addr 127.0.0.1:5576 --rc-user=rcadmin --rc-pass=RcMusic2026! vfs/refresh recursive=true
sudo docker restart navidrome-navidrome-1
Le restart container déclenche un full scan au démarrage (~20 min pour 16 000 titres). Vérifier avec getScanStatus ("scanning":false = terminé).
Solution pérenne
Full scan hebdomadaire chaque lundi à 3h UTC (navidrome_fullscan.sh) — garantit que tout nouvel album ajouté dans la semaine est indexé au plus tard le lundi matin.
REX — 2026-06-13 : FUSE corrompu / Symfonium inaccessible
Contexte
Après l'incident sécurité rclone du 2026-06-09 (CVE-2026-41179), le service kdrive-music.service a été relancé. Il est resté actif 4 jours sans crash apparent, mais le mount FUSE /home/debian/music était silencieusement corrompu.
Symptômes
- Symfonium (Subsonic) : erreur "trop d'erreurs, arrêt de lecture" sur tous les appareils portables
- Logs Navidrome :
transport endpoint is not connectedsur tous les fichiers audio systemctl status kdrive-music.service: active (running) depuis 3 jours — aucune indication du problème
Cause
Le process rclone était vivant mais la connexion noyau FUSE était morte. Pas de crash = pas de restart automatique par systemd.
Procédure de résolution
- Redémarrer le service rclone :
sudo systemctl restart kdrive-music.service - Vérifier que le mount répond :
ls /home/debian/music | head -5 - Redémarrer le container Navidrome — nécessaire même avec
:shared, car le container garde l'ancienne référence FUSE corrompue - Sur les appareils : force-fermer Symfonium et relancer
Notes
- La propagation
:sharedne suffit pas à propager un nouveau mount FUSE à un container déjà démarré — le container doit être redémarré. - Attention spool /tmp : un restart du service rclone peut créer un fichier
/tmp/rclone-spool*de plusieurs Go si des fichiers cachés sont marqués "dirty". Préférervfs/refresh(avec auth RC) au restart quand le FUSE n'est pas corrompu.
20_NodeExporter
node-exporter
| Image | prom/node-exporter:latest |
|---|---|
| Etat | Up 9 hours |
| Compose project | gemini_grafana |
| Reseau | gemini_grafana_monitor_net |
Ports
| Hote | Container | IP |
|---|---|---|
| 9100 | 9100/tcp | 0.0.0.0 |
| 9100 | 9100/tcp | :: |
Volumes
| Source (hote) | Destination | Type | Mode |
|---|---|---|---|
/proc | /host/proc | bind | ro |
/sys | /host/sys | bind | ro |
/ | /rootfs | bind | ro |
Integration Claude Code — API directe
| Statut MCP | Pas de MCP — API directe possible |
|---|---|
| Note technique | Exporte des métriques système (CPU, RAM, disque, réseau) au format Prometheus sur /metrics. Pas de MCP. Données consommées par Prometheus puis visualisées dans Grafana. |
Ce que nous pouvons faire ensemble
- Métriques système VPS (CPU load, RAM libre, espace disque, I/O)
- Accessible via requêtes PromQL sur Prometheus ou via l'API Grafana
21_Prometheus
prometheus
| Image | prom/prometheus:latest |
|---|---|
| Etat | Up 9 hours |
| Compose project | gemini_grafana |
| Reseau | gemini_grafana_monitor_net |
| Source | https://github.com/prometheus/prometheus |
Ports
| Hote | Container | IP |
|---|---|---|
| 9090 | 9090/tcp | 0.0.0.0 |
| 9090 | 9090/tcp | :: |
Volumes
| Source (hote) | Destination | Type | Mode |
|---|---|---|---|
/opt/monitoring/prometheus.yml | /etc/prometheus/prometheus.yml | bind | ro |
/opt/monitoring/prometheus_data | /prometheus | bind | rw |
Integration Claude Code — API directe
| Statut MCP | Pas de MCP — API directe possible |
|---|---|
| Note technique | API REST Prometheus sur /api/v1. Requêtes PromQL via /api/v1/query et /api/v1/query_range. Pas de MCP configuré — appels directs via PowerShell/Python. |
Ce que nous pouvons faire ensemble
- Requêtes PromQL pour métriques CPU, RAM, réseau, containers
- Interroger l'historique d'un container ou du système sur une période
- Détecter des anomalies ou pics de consommation
- Lister les targets et leurs états (up/down)
22_Readeck
readeck
| Image | codeberg.org/readeck/readeck:latest |
|---|---|
| Etat | Up 9 hours |
| Compose project | readeck |
| Reseau | readeck_default |
| URL | https://readeck.juxjux.ovh |
Ports
| Hote | Container | IP |
|---|---|---|
| 4567 | 8000/tcp | 0.0.0.0 |
| 4567 | 8000/tcp | :: |
Volumes
| Source (hote) | Destination | Type | Mode |
|---|---|---|---|
/home/debian/readeck/exports | /exports | bind | rw |
| /readeck | volume | rw |
/home/debian/readeck/data | /readeck/data | bind | rw |
Integration Claude Code — MCP
| Statut MCP | MCP actif |
|---|---|
| Outils (prefix) | mcp__readeck__ |
| Configuration | Script Python : C:\Users\eliob\.claude\mcp_readeck.py | Auth : token API Bearer (MFA actif sur le compte web) |
Outils disponibles
get_bookmarksget_bookmarkcreate_bookmarkupdate_bookmarkdelete_bookmarkget_labelsget_profile
Ce que nous pouvons faire ensemble
- Sauvegarder un article ou une page web depuis Claude Code
- Parcourir et rechercher les articles enregistrés
- Organiser les bookmarks avec des labels
- Mettre à jour le statut (lu/archivé) d'un article
- Supprimer des bookmarks obsolètes
Sauvegarde de la base de données
Sauvegarde automatique quotidienne de la base SQLite de Readeck vers kDrive Infomaniak. Mise en place le 2026-06-01.
Paramètres
| Script | /opt/backups/vps_backup.sh |
|---|---|
| Cron | Tous les jours à 2h du matin (0 2 * * *) |
| Type base | SQLite — /readeck/data/db.sqlite3 (dans le container) |
| Méthode | docker cp readeck:/readeck/data/db.sqlite3 |
| Taille base | ~8.5 Mo |
| Format archive | .7z (compression niveau 5) |
| Destination | kDrive Infomaniak — TOOJUX/jux_vps/readeck (dossier ID 1427922) |
| Rétention | 7 jours glissants |
| Nommage fichier | readeck_db_YYYY-MM-DD.7z |
Note
Le volume /readeck (non bindé) contient les fichiers des articles (images, HTML). La base SQLite ne couvre que les métadonnées et le texte extrait — les contenus médias ne sont pas inclus dans ce backup.
23_Syncthing
syncthing
| Image | syncthing/syncthing:latest |
|---|---|
| Version | v2.0.14 |
| Etat | Up 9 hours (healthy) |
| Compose project | syncthing |
| Reseau | syncthing_syncthing_net |
| URL | https://syncthing.juxjux.ovh |
| Source | https://github.com/syncthing/syncthing |
Ports
| Hote | Container | IP |
|---|---|---|
| 21027 | 21027/udp | 0.0.0.0 |
| 21027 | 21027/udp | :: |
| 22000 | 22000/tcp | 0.0.0.0 |
| 22000 | 22000/tcp | :: |
| 22000 | 22000/udp | 0.0.0.0 |
| 22000 | 22000/udp | :: |
| 8384 | 8384/tcp | 0.0.0.0 |
| 8384 | 8384/tcp | :: |
Volumes
| Source (hote) | Destination | Type | Mode |
|---|---|---|---|
| /var/syncthing | volume | rw |
/home/debian/Documents | /var/syncthing/Documents | bind | rw |
/home/debian/Public | /var/syncthing/Public | bind | rw |
/home/debian/docker/syncthing/config | /var/syncthing/config | bind | rw |
/home/debian/docker/syncthing/data1 | /var/syncthing/data1 | bind | rw |
/home/debian/docker/syncthing/data2 | /var/syncthing/data2 | bind | rw |
/home/debian/joplin-data | /var/syncthing/joplin-data | bind | rw |
Integration Claude Code — MCP
| Statut MCP | MCP actif |
|---|---|
| Outils (prefix) | mcp__syncthing__ |
| Configuration | Script Python : C:\Users\eliob\.claude\mcp_syncthing.py | Auth : clé API dans header X-API-Key |
Outils disponibles
pingget_statusget_versionget_devicesget_device_statsget_foldersget_folder_statusget_folder_statsget_folder_errorsget_connectionsget_completionpause_deviceresume_devicescan_folder
Ce que nous pouvons faire ensemble
- Vérifier l'état de synchronisation de chaque dossier
- Voir la progression de sync entre appareils (PC ↔ VPS)
- Détecter des erreurs de synchronisation
- Déclencher un scan d'un dossier manuellement
- Mettre en pause ou reprendre la sync avec un appareil
- Consulter les statistiques de transfert par device
24_Yourls
yourls
| Image | yourls:latest |
|---|---|
| Etat | Up 9 hours |
| Compose project | yourls |
| Reseau | yourls_default |
| URL | https://yourls.juxjux.ovh |
Ports
| Hote | Container | IP |
|---|---|---|
| 8085 | 80/tcp | 0.0.0.0 |
| 8085 | 80/tcp | :: |
Volumes
| Source (hote) | Destination | Type | Mode |
|---|---|---|---|
/var/lib/docker/volumes/yourls_yourls_plugins/_data | /var/www/html/user/plugins | volume | rw |
/home/debian/docker/yourls/ports.conf | /etc/apache2/ports.conf | bind | rw |
/home/debian/docker/yourls/000-default.conf | /etc/apache2/sites-available/000-default.conf | bind | rw |
/var/lib/docker/volumes/yourls_yourls_html/_data | /var/www/html | volume | rw |
/var/lib/docker/volumes/yourls_yourls_user/_data | /var/www/html/user | volume | rw |
yourls-db
| Image | mysql:8.0 |
|---|---|
| Etat | Up 9 hours (healthy) |
| Compose project | yourls |
| Reseau | yourls_default |
| URL | https://yourls.juxjux.ovh |
Volumes
| Source (hote) | Destination | Type | Mode |
|---|---|---|---|
/var/lib/docker/volumes/yourls_yourls_mysql_data/_data | /var/lib/mysql | volume | rw |
Integration Claude Code — API directe
| Statut MCP | Pas de MCP — API directe possible |
|---|---|
| Note technique | API REST Yourls sur /yourls-api.php. Auth : signature HMAC ou token. Pas de MCP configuré — appels directs possibles. |
Ce que nous pouvons faire ensemble
- Créer des URLs courtes personnalisées depuis Claude Code
- Lister et gérer les liens raccourcis existants
- Consulter les statistiques de clics sur un lien
25_StirlingPDF
stirling-pdf
Suite complète de manipulation de PDF — open source, auto-hébergée
| Image | stirlingtools/stirling-pdf:latest |
|---|---|
| Etat | Up (healthy) |
| Compose project | stirlingpdf |
| Reseau | stirlingpdf_default |
| URL | https://spdf.juxjux.ovh |
| Source | https://github.com/Stirling-Tools/Stirling-PDF |
Ports
| Hote | Container | IP |
|---|---|---|
| 8090 | 8080/tcp | 0.0.0.0 |
Variables
| Variable | Valeur |
|---|---|
| DOCKER_ENABLE_SECURITY | false |
| LANGS | fr_FR |
Volumes
| Hote | Container |
|---|---|
| /opt/stirling-pdf/configs | /configs |
| /opt/stirling-pdf/logs | /logs |
Notes
- Remplacera BentoPDF (bento.juxjux.ovh / port 8089) quand la transition sera faite
- A terme : récupérer le domaine pdf.juxjux.ovh et désactiver la stack bentopdf
- Sécurité désactivée (DOCKER_ENABLE_SECURITY=false)
Integration Claude Code
| Statut MCP | Pas de MCP — API directe possible |
|---|---|
| Note technique | API REST sur /api — scriptable via PowerShell/Python httpx. |
Ce que nous pouvons faire ensemble
- Fusion, découpage, compression, conversion PDF via API REST
- OCR, extraction de texte, filigrane, rotation
- Automatisation dans des scripts Claude Code
26_JDownloader
jdownloader
Gestionnaire de téléchargements avancé — interface web noVNC, supporte hôtes premium et lien direct
| Image | jlesage/jdownloader-2:latest |
|---|---|
| Etat | Up (running) |
| Compose project | jdownloader |
| Reseau | jdownloader_default |
| URL | https://jdownloader.juxjux.ovh |
| Source | https://github.com/jlesage/docker-jdownloader-2 |
Ports
| Hote | Container | IP |
|---|---|---|
| 5800 | 5800/tcp | 127.0.0.1 |
Variables
| Variable | Valeur |
|---|---|
| USER_ID | 1000 |
| GROUP_ID | 1000 |
| TZ | Europe/Paris |
Volumes
| Hote | Container |
|---|---|
| /opt/jdownloader/config | /config |
| /home/debian/downloads | /output |
Notes
- Interface noVNC accessible via navigateur — pas besoin de client VNC
- Port 5800 lié à
127.0.0.1uniquement — non exposé directement à l'internet - Au 1er lancement, JDownloader télécharge ses composants (~1 min) avant d'afficher l'UI
- Cert SSL Let's Encrypt valide jusqu'au 2026-08-31 (renouvellement automatique certbot)
- Installé le 2026-06-02 via stack Portainer (ID 90)
Integration Claude Code
| Statut MCP | Pas de MCP — interface web uniquement (noVNC) |
|---|---|
| Note technique | Pas d'API REST publique documentée. Pilotage uniquement via l'interface graphique. |
Ce que nous pouvons faire ensemble
- Vérifier l'état du container via l'API Portainer
- Redémarrer le container si l'interface ne répond plus
- Lister les fichiers téléchargés dans
/home/debian/downloadsvia SSH
27 - Rustdesk
RustDesk — Serveur auto-hébergé (hbbs/hbbr)
Qu'est-ce que c'est
RustDesk est un logiciel de bureau à distance open-source (alternative à TeamViewer/AnyDesk). Il repose sur deux briques serveur :
- hbbs (ID/rendezvous server) — enregistre les IDs des clients, gère le heartbeat, tente d'établir une connexion P2P directe.
- hbbr (relay server) — relaie le flux quand le P2P direct échoue (NAT symétrique, pare-feu strict, etc.).
Auto-héberger ces deux services évite de dépendre des serveurs publics RustDesk (rendezvous/relais tiers) : tout le trafic de contrôle passe par une infrastructure qu'on maîtrise.
Poids du service Docker
| Élément | Valeur |
|---|---|
Image rustdesk/rustdesk-server:latest (amd64) |
5,61 Mo compressée |
| Image (arm64) | 5,2 Mo |
| Image (armv7) | 5,04 Mo |
| Nombre de containers | 2 (hbbs + hbbr) |
| RAM au repos | quelques dizaines de Mo par container (binaires Rust natifs, pas de VM/interpréteur) |
| CPU au repos | négligeable |
| CPU/RAM en charge | dépend du nombre de sessions actives relayées par hbbr (le flux vidéo transite par lui si pas de P2P direct) — reste très léger pour un usage perso/familial (quelques sessions simultanées max) |
Pour comparaison, c'est très inférieur au poids des autres containers déjà en place sur le VPS Jux (BookStack/MariaDB, Immich, etc.).
Ports requis (conditions réseau)
| Port | Protocole | Service | Rôle |
|---|---|---|---|
| 21115 | TCP | hbbs | Test de type NAT |
| 21116 | TCP + UDP | hbbs | UDP = enregistrement ID + heartbeat / TCP = hole punching + connexion |
| 21117 | TCP | hbbr | Service de relais |
| 21118 | TCP | hbbs | Client web (optionnel) |
| 21119 | TCP | hbbr | Client web (optionnel) |
| 21114 | TCP | hbbs | Console web — Pro uniquement, pas utile en OSS |
Si le client web n'est pas utilisé, 21118/21119 peuvent rester fermés (recommandé : ces deux ports font confiance aux en-têtes X-Real-IP/X-Forwarded-For sans les valider, donc à n'exposer que derrière un reverse proxy qui les fixe lui-même, jamais en direct).
docker-compose.yml (référence officielle RustDesk)
services:
hbbs:
container_name: hbbs
image: rustdesk/rustdesk-server:latest
command: hbbs
volumes:
- ./data:/root
network_mode: "host"
depends_on:
- hbbr
restart: unless-stopped
hbbr:
container_name: hbbr
image: rustdesk/rustdesk-server:latest
command: hbbr
volumes:
- ./data:/root
network_mode: "host"
restart: unless-stopped
network_mode: hostest la méthode recommandée sous Linux : hbbs/hbbr voient l'IP réelle du client au lieu de l'IP interne du container. Fonctionne uniquement sur Linux (donc OK sur le VPS Debian, pas sur un NAS DSM qui a ses propres contraintes réseau — voir plus bas).- Alternative sans host networking (mapping de ports classique, pour Portainer/stack isolée) :
services:
hbbs:
container_name: hbbs
image: rustdesk/rustdesk-server:latest
command: hbbs -r rustdesk.exemple.com:21117
ports:
- "21115:21115"
- "21116:21116"
- "21116:21116/udp"
- "21118:21118"
volumes:
- ./data:/root
depends_on:
- hbbr
restart: unless-stopped
hbbr:
container_name: hbbr
image: rustdesk/rustdesk-server:latest
command: hbbr
ports:
- "21117:21117"
- "21119:21119"
volumes:
- ./data:/root
restart: unless-stopped
Variable d'environnement utile : ALWAYS_USE_RELAY=Y sur hbbs pour forcer systématiquement le passage par le relais (utile si on veut masquer les IP réelles des clients, au prix d'un peu plus de charge sur hbbr).
Clé de chiffrement et configuration client
- Au premier démarrage, hbbs génère une paire de clés dans le volume
./data: le fichierid_ed25519.pubcontient la clé publique à distribuer aux clients. - Configuration côté client RustDesk (menu ⋮ → Réseau, déverrouiller) :
- ID Server : IP ou domaine du VPS (ex.
vps.juxjux.ovhou l'IP directe) - Relay Server : peut rester vide (déduit automatiquement, sinon
IP:21117) - Key : contenu de
id_ed25519.pub
- ID Server : IP ou domaine du VPS (ex.
- Export/import de config possible entre clients (bouton "Export Server Config"), pratique pour déployer sur plusieurs machines (PC Windows, Ubuntu, etc.) sans ressaisir.
VPS Jux vs NAS Synology sasnexte — analyse
RustDesk propose officiellement un guide d'installation Synology (DSM 6 et DSM 7.2/Container Manager), donc l'hébergement NAS est une voie supportée en soi — la question n'est pas la faisabilité technique mais la joignabilité réseau.
| Critère | VPS Jux (51.77.141.54) | NAS sasnexte (82.66.244.248) |
|---|---|---|
| IP publique fixe | Oui | Non confirmée — SSH déjà signalé comme parfois inaccessible depuis l'extérieur (fail2ban/whitelist) |
network_mode: host (recommandé Linux) |
Disponible (Debian) | Non disponible sous DSM (Docker/Container Manager Synology tourne dans une couche réseau propriétaire) — nécessite le mapping de ports classique + redirection sur la box |
| Port forwarding | Déjà maîtrisé (nginx, certbot, ufw) | Dépend de la box du FAI, potentiellement CGNAT résidentiel |
| Exposition déjà en place | 34 containers en prod, expérience du durcissement (incident du 9 juin 2026) | Usage actuel = uniquement syncs rclone sortants vers kDrive, pas de service entrant exposé |
| Impact en cas d'indisponibilité | VPS pro, uptime élevé | Dépend de l'alimentation/connexion internet du domicile |
Conclusion : le VPS reste le choix le plus robuste pour un usage "accès à distance depuis n'importe où". Le NAS serait une option seulement si l'IP publique/DDNS et le port forwarding sont déjà fiables — ce qui n'est pas le cas aujourd'hui d'après le comportement SSH observé.
Prochaine étape proposée
Ajouter la stack rustdesk sur le VPS (Portainer, comme les autres services), avec ufw restreint aux ports 21115-21119 (TCP+UDP sur 21116) et 21118/21119 fermés tant que le client web n'est pas nécessaire.
Incident client Windows — BSOD à l'installation (2026-07-31)
Contexte : installation du client RustDesk sur le PC Windows 10 (eliob). L'installation s'est terminée par plusieurs écrans bleus consécutifs.
Diagnostic
- Analyse de l'Observateur d'événements (
Microsoft-Windows-WER-SystemErrorReporting) : crash à 06:27:20 avec bugcheck0x50(PAGE_FAULT_IN_NONPAGED_AREA), dump complet dansC:\WINDOWS\MEMORY.DMP(2,4 Go). - Corrélation temporelle exacte avec l'extraction de deux composants pilotes bundlés par le client RustDesk :
C:\Program Files\RustDesk\usbmmidd_v2— pilote d'écran virtuel USBMMIDD (permet le contrôle à distance sans moniteur physique branché)C:\Program Files\RustDesk\drivers\RustDeskPrinterDriver— pilote d'imprimante virtuelle (impression à distance)
- Vérification : ni l'un ni l'autre n'était enregistré comme périphérique actif (
Get-PnpDevice,pnputil /enum-drivers) après coup → l'installation du driver a fait planter le noyau avant de s'enregistrer. Un problème connu et documenté côté communauté RustDesk : le driverusbmmidd(ancien, non WHQL sur les builds récentes de Windows 10) provoque des BSOD à l'installation sur certaines configs. - Point distinct identifié en passant : la machine a un historique chronique de BSOD
0x9f(DRIVER_POWER_STATE_FAILURE) récurrent environ une fois par mois depuis janvier 2026 (Kernel-Powerevent 41), sans lien avec RustDesk — probablement un driver qui répond mal à la mise en veille. Non résolu, à creuser séparément si besoin.
Fix appliqué
Neutralisation des deux dossiers de drivers sans désinstaller RustDesk (le contrôle à distance standard, moniteur physique branché, ne dépend pas d'eux) :
Stop-Service -Name "RustDesk" -Force
Stop-Process -Name "rustdesk" -Force -ErrorAction SilentlyContinue
Rename-Item "C:\Program Files\RustDesk\usbmmidd_v2" "usbmmidd_v2.disabled"
Rename-Item "C:\Program Files\RustDesk\drivers\RustDeskPrinterDriver" "RustDeskPrinterDriver.disabled"
Start-Service -Name "RustDesk"
Note importante : ces commandes nécessitent une session PowerShell réellement élevée (clic droit → "Exécuter en tant qu'administrateur", accepter l'UAC). Une session non élevée renvoie la même erreur Impossible d'ouvrir le service aussi bien pour Stop-Service que pour le renommage des dossiers dans Program Files — ça peut faire croire à tort qu'on est admin alors que non.
Résultat
- Service
RustDesk Service:Running - Contrôle à distance classique opérationnel (vérifié : process
RustDesk.exeactif, service démarré) - Écran virtuel et impression à distance désactivés (fonctionnalités non utilisées) — évite que RustDesk retente d'installer ces drivers automatiquement
- Mot de passe permanent + 2FA activés par Julien le 2026-07-31 (menu Sécurité de RustDesk) → accès non attendu opérationnel : ce PC est joignable via RustDesk sans présence devant l'écran, ID + mot de passe permanent (2FA en complément).
Traversée VPS — client configuré (2026-07-31)
Le client RustDesk du PC eliob passe désormais par le serveur auto-hébergé (hbbs/hbbr sur le VPS Jux, voir plus haut) au lieu des relais publics RustDesk. Confirmé côté serveur : containers hbbs/hbbr up, ufw ouvert sur 21115-21117 (v4+v6), clé publique id_ed25519.pub en place. Tout le trafic de contrôle à distance de ce PC transite donc par une infrastructure maîtrisée plutôt que par un tiers.
D_la solution contacts et calendrier
Solution d'unification des contacts et du calendrier de Julien.
État au 3 août 2026 — déployé et opérationnel de bout en bout. Seul vdirsyncer (agrégation Google/Infomaniak) reste à faire.
1. Objectif
Unifier la base de contacts et de calendriers, dispersée entre plusieurs sources (Google, Infomaniak, téléphone), autour d'un point central auto-hébergé sur le VPS juxjux.ovh, synchronisé vers tous les clients existants.
Baïkal est la source de vérité unique. Roundcube, InfCloud et DAVx5 en sont des clients ; vdirsyncer sera le seul composant qui écrit depuis l'extérieur vers Baïkal.
2. Architecture réellement déployée
| Composant | Rôle | Emplacement | État |
|---|---|---|---|
| Baïkal | Serveur CardDAV + CalDAV, stockage central | Docker, VPS juxjux | En service |
| InfCloud | Agenda et contacts web | Statique, servi par nginx | En service |
| Roundcube | Interface web des contacts | Docker, VPS juxjux | En service |
| Nginx | Reverse proxy HTTPS | Hôte VPS | En service |
| DAVx5 | Pont de synchronisation vers Android | Téléphone | Opérationnel |
| Fossify Agenda | Client calendrier | Téléphone (via DAVx5) | Opérationnel |
| vdirsyncer | Agrège Google et Infomaniak vers Baïkal | VPS, cron | Non déployé |
| Thunderbird | Client mail, indépendant de ce circuit | Téléphone | Inchangé |
3. Accès
| Service | URL | Identifiant |
|---|---|---|
| Agenda + contacts web | https://baikal.juxjux.ovh/infcloud/ | Julien (compte Baïkal) |
| Contacts web (Roundcube) | https://secretariat.juxjux.ovh | julien.bertrand@ik.me (compte mail Infomaniak) |
| Administration Baïkal | https://baikal.juxjux.ovh/admin/ | compte admin Baïkal |
| Découverte DAV (DAVx5) | https://baikal.juxjux.ovh/dav.php/ |
Julien |
Utilisateur Baïkal : Julien — avec un J majuscule. La casse compte dans les URLs DAV.
- Principal :
https://baikal.juxjux.ovh/dav.php/principals/Julien/ - Contacts :
https://baikal.juxjux.ovh/dav.php/addressbooks/Julien/default/ - Calendrier :
https://baikal.juxjux.ovh/dav.php/calendars/Julien/default/
Certificats Let's Encrypt valides jusqu'au 1er novembre 2026 pour les deux domaines. Celui de baikal.juxjux.ovh existait déjà mais avait expiré le 8 février 2026 (vestige d'une tentative antérieure) ; il a été renouvelé le 3 août.
4. Déploiement
Stack sur le VPS : /home/debian/baikal/docker-compose.yml, projet compose baikal.
Sources versionnées : Syncthing/Jux_univers/Jux-scripts/Baikal-Contacts/.
| Fichier | Rôle |
|---|---|
docker-compose.yml |
Stack Baïkal + Roundcube |
baikal.juxjux.ovh.conf |
Vhost Baïkal (.well-known forcés en HTTPS + service d'InfCloud) |
secretariat.juxjux.ovh.conf |
Vhost Roundcube |
infcloud-config.js |
Configuration InfCloud |
finaliser_tls.sh |
Vérifie le DNS puis lance certbot |
vps_backup.sh |
Script de sauvegarde complet, Baïkal inclus |
push_bookstack.py |
Publication de cette page via l'API BookStack |
cd /home/debian/baikal && sudo docker compose -p baikal up -d
| Service | Image | Port local | Base | RAM |
|---|---|---|---|---|
| baikal | ckulka/baikal:nginx |
127.0.0.1:8088 | SQLite | ~38 Mo |
| roundcube | roundcube/roundcubemail:latest (1.7.2) |
127.0.0.1:8083 | SQLite | ~32 Mo |
| InfCloud | fichiers statiques (13 Mo sur disque) | — | aucune | 0 |
Les deux containers pèsent environ 70 Mo au total, contre environ 600 Mo avec l'architecture MariaDB initialement prévue. Ce choix était important : le VPS était en pression mémoire au moment du déploiement (swap à 3,8/4,0 Go).
5. Écarts avec le plan initial
Le plan préparé prévoyait une configuration qui ne pouvait pas fonctionner en l'état. Écarts constatés et corrigés :
| Point | Prévu | Réel | Raison |
|---|---|---|---|
| Port Baïkal | 8081 | 8088 | 8081 est occupé par FreshRSS. 8088 correspond au vhost baikal.juxjux.ovh préexistant |
| Port Roundcube | 8082 | 8083 | 8082 est ciblé par un vhost nextcloud mort |
| Domaine Roundcube | mail.juxjux.ovh |
secretariat.juxjux.ovh |
Aucun DNS n'existait ; mail. prêtait à confusion avec les MX OVH du domaine |
| Base Roundcube | MariaDB | SQLite | ~400 Mo de RAM économisés, suffisant en mono-utilisateur |
| Vhost Baïkal | À créer | Déjà présent | Le fichier baikal.conf préparé n'a pas servi |
| Agenda web | Plugin calendar Roundcube | InfCloud | Plugin inutilisable, voir §6.2 |
6. Pièges rencontrés
6.1 Les plugins carddav et calendar ne sont pas dans l'image Roundcube
L'image officielle ne fournit ni carddav ni calendar. Les déclarer dans ROUNDCUBEMAIL_PLUGINS ne fait que les activer — s'ils sont absents, Roundcube part en erreur fatale.
Il faut les faire installer par composer au démarrage, via ROUNDCUBEMAIL_COMPOSER_PLUGINS (et non ROUNDCUBEMAIL_INSTALL_PLUGINS, qui n'existe pas dans cette image) :
ROUNDCUBEMAIL_COMPOSER_PLUGINS: "roundcube/carddav"
ROUNDCUBEMAIL_PLUGINS: "carddav"
Le premier démarrage est alors plus long (téléchargement composer).
6.2 Le plugin calendar de Roundcube est une impasse
Trois obstacles successifs, testés le 3 août :
a) Il casse le tout premier démarrage. Le script d'initialisation de base de kolab/calendar s'exécute avant que l'entrypoint n'écrive la configuration Roundcube : il tombe sur le DSN MySQL par défaut et échoue en SQLSTATE[HY000] [2002] No such file or directory. Cette erreur fatale empêche la régénération de l'autoloader composer, ce qui casse aussi le plugin carddav :
PHP Fatal error: Uncaught Error: Interface
"MStilkerich\RCMCardDAV\Frontend\RcmInterface" not found
in /var/www/html/plugins/carddav/carddav.php:43
Symptôme : HTTP 500 permanent, alors que les fichiers du plugin sont bien présents sur le disque — c'est vendor/composer/autoload_psr4.php qui ne contient aucune entrée carddav.
b) Ce premier obstacle est contournable. Réinstallé après que Roundcube ait été initialisé une première fois, la configuration existe déjà dans le volume et l'initialisation aboutit (Creating database schema... [OK]). Vérifié.
c) Mais le plugin ne sait pas parler à Baïkal. La seule version installable, kolab/calendar 3.2.9.1, ne livre que les pilotes database, kolab et ldap — aucun pilote caldav. Il ne créerait qu'un agenda local dans Roundcube, sans lien avec Baïkal ni le téléphone : pire qu'inutile, on pourrait y saisir des rendez-vous en croyant qu'ils se synchronisent.
Les versions qui embarquent le pilote CalDAV (3.5.7, 3.6.1) dépendent de kolab/libkolab, qui réclame pear/http_request2 — paquet bloqué par composer pour faille de sécurité (PKSA-jrt3-xndd-g4sz). Ne pas contourner ce garde-fou sur un service exposé sur internet.
Conclusion : agenda web assuré par InfCloud (§7), plugin calendar définitivement écarté.
6.3 Baïkal ignore X-Forwarded-Proto — fuite HTTP sur la découverte
Baïkal ne tient pas compte de X-Forwarded-Proto et générait ses redirections de découverte en HTTP nu :
/.well-known/carddav -> http://baikal.juxjux.ovh/dav.php
C'est exactement le risque identifié dès la conception : CardDAV et CalDAV envoient les identifiants à chaque synchronisation. Un client suivant cette redirection part sur du HTTP.
Corrigé en court-circuitant Baïkal directement dans le vhost :
location = /.well-known/carddav {
return 301 https://$host/dav.php/;
}
location = /.well-known/caldav {
return 301 https://$host/dav.php/;
}
À vérifier après tout reload nginx : le rechargement n'est pas instantané, un test lancé dans la foulée peut encore montrer l'ancien comportement.
6.4 Roundcube exige un serveur IMAP pour authentifier
Roundcube n'a pas de base d'utilisateurs propre : son écran de login valide les identifiants contre le serveur IMAP configuré. Sans IMAP joignable, aucune connexion n'est possible — donc aucun accès aux contacts non plus.
L'idée d'un Roundcube « contacts et agenda seulement, sans IMAP » n'est pas réalisable. La configuration retenue pointe vers ssl://mail.infomaniak.com:993, ce qui couvre le compte julien.bertrand@ik.me (le domaine ik.me est servi par l'infrastructure Infomaniak).
Si un jour le compte passe en double authentification, il faudra générer un mot de passe d'application Infomaniak.
6.5 Baïkal doit être installé en SQLite
L'installeur Baïkal propose MySQL ou SQLite. Choisir SQLite : la stack ne contient aucun serveur MySQL, cocher « Enable MySQL » mène à une impasse. Base à /var/www/baikal/Specific/db/db.sqlite, dans le volume baikal-data.
7. InfCloud — l'agenda web
Client CalDAV/CardDAV entièrement côté navigateur : aucun backend, aucune base, du HTML/JS servi en statique par nginx. Affiche agenda et contacts.
- Source officielle :
https://www.inf-it.com/InfCloud_0.13.1.zip(3,9 Mo, sha2569fa95edd2dcc2b864a10b503ab9220895ea28d4c5541ab02117de1511d5464d4) - Installé dans
/home/debian/baikal/infcloud, propriétairewww-data - Servi sur le même domaine que Baïkal (
/infcloud/) et non sur un sous-domaine dédié : InfCloud interroge/dav.php/en direct depuis le navigateur ; depuis une autre origine il aurait fallu ouvrir du CORS sur les méthodes DAV de Baïkal, ce qui est fragile et l'affaiblirait. Même origine = aucun CORS. - Dossier
auth/supprimé : module PHP d'authentification par proxy inutilisé ici. nginx ne traite pas le PHP à cet emplacement — servis en statique, ces fichiers.incauraient exposé leur contenu en clair.
Réserve assumée : projet figé depuis 2015, interface datée, embarque jQuery 2.1.4. Acceptable parce qu'il n'a aucun composant serveur : rien à maintenir, rien à patcher. La seule alternative maintenue serait SOGo, au prix d'environ 500 Mo de RAM et d'une base PostgreSQL.
7.1 Les trois pièges d'InfCloud
a) Le bloc regex du vhost avale tous les JS. Le vhost Baïkal contient déjà :
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { proxy_pass http://127.0.0.1:8088; }
En nginx, un bloc regex ~* a priorité sur un bloc préfixe ordinaire. Tous les fichiers JavaScript d'InfCloud auraient donc été proxifiés vers Baïkal. Comme InfCloud est presque intégralement du JavaScript, la page serait restée blanche — symptôme difficile à diagnostiquer. Il faut ^~, qui passe devant les regex :
location ^~ /infcloud/ {
alias /home/debian/baikal/infcloud/;
index index.html;
location ~ /\. { deny all; }
}
b) L'endpoint par défaut vise DAViCal. Le config.js livré pointe /caldav.php/ ; Baïkal expose /dav.php/.
c) Le href doit viser les principals, pas la racine DAV. InfCloud accole le nom d'utilisateur au href. Avec /dav.php/ il demandait /dav.php/Julien/ → 404. La documentation du fichier le précise : « globalNetworkCheckSettings : principal URL WITHOUT the USER/ part ». Chez Baïkal, la bonne valeur est donc :
'/dav.php/principals/',
Après toute modification de config.js, rechargement forcé du navigateur (Ctrl+Maj+R) : le fichier est mis en cache.
7.2 Digest → Basic : le blocage d'authentification
Baïkal était configuré en dav_auth_type: Digest et annonçait WWW-Authenticate: Digest realm="BaikalDAV".
InfCloud ne sait faire que du Basic. Ses requêtes partaient donc en 401 en boucle, alors que DAVx5 — qui gère Digest — fonctionnait parfaitement avec le même compte. Le symptôme prêtait à confusion : les identifiants étaient bons.
Diagnostic par les logs nginx, où le champ utilisateur est renseigné mais la réponse reste 401 :
83.195.45.93 - Julien "PROPFIND /dav.php/ HTTP/2.0" 401
Correctif : dav_auth_type: Basic dans /var/www/baikal/config/baikal.yaml, puis docker restart baikal.
Ce n'est pas un pis-aller. Digest repose sur MD5, est considéré comme obsolète, et impose au serveur de stocker une empreinte exploitable ; Basic sur TLS est aujourd'hui la recommandation, et tout est en HTTPS ici, y compris les redirections de découverte (§6.3).
Les mots de passe restent valides : Baïkal calcule la même empreinte md5(username:auth_realm:password) dans les deux modes (Baikal\Core\PDOBasicAuth::validateUserPass), avec auth_realm: BaikalDAV conservé en interne — même si le serveur annonce désormais realm="sabre/dav" côté client. Rien à redéfinir, DAVx5 bascule tout seul.
Sauvegarde : /var/www/baikal/config/baikal.yaml.bak-260803-digest (dans le container).
8. Sauvegarde
Baïkal a été ajouté à /opt/backups/vps_backup.sh le 3 août 2026 (cron quotidien à 2h UTC).
- Dossier kDrive de destination : 1467771 (
SYNC-pour_VPS/backups/baikal) - Le bilan de fin de log passe de 5 à 6 services (le total est calculé dynamiquement, pas codé en dur)
- Sauvegarde de l'ancien script :
/opt/backups/vps_backup.sh.bak-260803
La fonction archive deux volumes, via un tar intermédiaire puis 7z :
Specific/— la basedb.sqlite(contacts et calendriers)config/—baikal.yaml(paramètres et empreinte du mot de passe admin)
Sans le second, la restauration est incomplète. Testée le 3 août : upload HTTP 200, aucun résidu temporaire.
InfCloud n'a pas besoin d'être sauvegardé (fichiers statiques réinstallables), mais son config.js est versionné dans Jux-scripts/Baikal-Contacts/.
9. Vérifications effectuées le 3 août 2026
| Test | Résultat |
|---|---|
GET /dav.php/ |
HTTP 401 — authentification bien exigée |
PROPFIND /dav.php/ |
HTTP 401 et non 405 — nginx laisse passer les méthodes DAV étendues |
.well-known/carddav et caldav |
301 vers HTTPS |
| Installation Baïkal | Utilisateur Julien, carnet et calendrier default créés |
| Login Roundcube | IMAP Infomaniak accepté |
| Découverte CardDAV Roundcube | Carnet résolu à .../dav.php/addressbooks/Julien/default/ |
| Écriture d'un contact | vCard 3.0 écrite par RCMCardDAV v5.1.3, relue dans Baïkal, accents UTF-8 préservés |
| Synchronisation DAVx5 | 5 rendez-vous d'août écrits dans Baïkal par DAVx5/4.5.18-ose, synctoken du calendrier à 6 |
| InfCloud | 32 ressources servies en 200 ; PROPFIND sur principals, addressbooks et calendars tous en 207 |
| Dotfiles InfCloud | .htaccess bloqué en 403 |
| Sauvegarde Baïkal | Archive uploadée sur kDrive, HTTP 200 |
Note : dans la table carddav_addressbooks de Roundcube, une seconde ligne nommée %N avec une URL vide n'est pas une erreur — c'est le template de rcmcarddav v5, qui porte les réglages appliqués aux carnets découverts.
10. Reste à faire
10.1 vdirsyncer — agrégation Google et Infomaniak
Seule brique du plan initial encore absente. Objectif : faire remonter dans Baïkal les contacts existants sur Google et Infomaniak, pour que Baïkal devienne le point central réel et pas un silo de plus.
- Google Contacts : CardDAV via
https://www.google.com/carddav/v1/principals/EMAIL/— nécessite un mot de passe d'application (compte en 2FA) - Infomaniak : CardDAV natif, identifiants standards du compte mail
- vdirsyncer : outil CLI léger, une paire de synchronisation par source, exécuté par cron sur le VPS
Décision à prendre avant déploiement :
- one-way (Google/Infomaniak → Baïkal, lecture seule) : sans risque, mais les modifications faites dans Baïkal ne remontent pas vers Google
- two-way : tout reste aligné, mais un conflit ou une erreur de configuration peut propager des suppressions dans les deux sens
Recommandation : démarrer en one-way le temps de vérifier que l'import est fidèle, puis basculer si besoin.
10.2 Nettoyage
Quatre vhosts morts traînent dans /etc/nginx/sites-enabled/, vestiges des tentatives précédentes : radicale, agendav, infcloud, nextcloud. Le dernier cible le port 8082, ce qui a contraint le choix du port de Roundcube. Attention : le vhost nommé radicale.juxjux.ovh sert en réalité Readeck — ne pas le supprimer sans vérifier.
11. Checklist sécurité
- Aucun mot de passe
CHANGE_ME_...en production — la bascule vers SQLite a supprimé les identifiants MariaDB du compose - HTTPS forcé sur les deux vhosts (redirection 80 vers 443)
- Certificats Let's Encrypt valides, renouvellement automatique certbot en place
- Découverte DAV forcée en HTTPS (§6.3)
- Authentification Basic uniquement sur TLS (§7.2)
- Les deux containers n'écoutent que sur
127.0.0.1— seul nginx les expose - Module PHP
auth/d'InfCloud supprimé, dotfiles bloqués - Sauvegarde quotidienne des volumes Baïkal vers kDrive
- Mot de passe d'application dédié pour l'accès CardDAV Google — à faire au moment de vdirsyncer
12. Commandes utiles
# État de la stack
sudo docker ps --filter name=baikal --filter name=roundcube
# Logs
sudo docker logs roundcube --tail 50
sudo docker logs baikal --tail 50
# Redéployer
cd /home/debian/baikal && sudo docker compose -p baikal up -d
# Inspecter la base Baïkal
sudo docker cp baikal:/var/www/baikal/Specific/db/db.sqlite /tmp/bk.sqlite
sudo sqlite3 /tmp/bk.sqlite "SELECT COUNT(*) FROM cards;"
sudo sqlite3 /tmp/bk.sqlite "SELECT COUNT(*) FROM calendarobjects;"
sudo sqlite3 /tmp/bk.sqlite "SELECT id, username FROM users;"
# Méthode d'authentification annoncée par Baïkal
curl -s -D - -o /dev/null -X PROPFIND -H 'Depth: 0' \
https://baikal.juxjux.ovh/dav.php/ | grep -i www-authenticate
# Suivre les requêtes DAV des clients (DAVx5, InfCloud, Roundcube)
sudo tail -f /var/log/nginx/access.log | grep dav.php
# Vérifier la découverte DAV
curl -s -o /dev/null -w "%{http_code} -> %{redirect_url}\n" \
https://baikal.juxjux.ovh/.well-known/carddav
13. Choix d'architecture — pourquoi ces outils
Radicale écarté : stockage fichier brut, pas de vraie gestion. La stack Radicale/InfCloud initialement envisagée n'a pas été mise en place — seul InfCloud a finalement été retenu, en client de Baïkal.
Nextcloud écarté : trop lourd pour l'usage visé (PHP-FPM + base + Redis + écosystème complet), alors que le VPS fait déjà tourner PostGIS, Metabase, BookStack, FreshRSS.
Baïkal retenu : léger, CardDAV et CalDAV natifs, interface d'administration suffisante. Développé par des bénévoles sous l'organisation sabre-io (mainteneurs de SabreDAV, la librairie sous-jacente) — pas de société commerciale derrière, mais communauté active et outil robuste pour un usage personnel sur la durée.
Roundcube retenu comme interface de saisie des contacts, Baïkal n'ayant pas de vraie UI de consultation : léger, traduit en français, projet actif (version 1.7.2 en août 2026). A rejoint la famille Nextcloud en 2023 tout en restant indépendant, sous licence GPL. Réserves constatées à l'usage : il impose une authentification IMAP (§6.4) et ne couvre pas l'agenda (§6.2).
InfCloud retenu pour l'agenda web : sans backend, donc sans coût mémoire ni surface d'attaque serveur, et couvre agenda et contacts. Ancien mais fonctionnel.
SOGo envisagé et écarté : suite complète et maintenue, mais environ 500 Mo de RAM et une base PostgreSQL sur un VPS déjà en pression mémoire, et il aurait fait doublon avec Roundcube.
Thunderbird containerisé (VNC/noVNC) envisagé puis écarté : fonctionnel mais plus lourd et moins adapté au multi-accès qu'un vrai webmail.
E_la gestion du SWAP du VPS par Claude
REX 260803 — Session Claude sur le VPS Jux
Session du 2026-08-02 (soir) au 2026-08-03 (matin). Quatre chantiers, tous appliqués et vérifiés. Le sujet principal de cette page — le swap — est traité en partie 1 ; les autres chantiers suivent car ils s'expliquent mutuellement (l'allègement JVM est ce qui a fait apparaître la question du swap).
| # | Chantier | État | Gain / résultat |
|---|---|---|---|
| 1 | Swap saturé à 95 % | Résolu | 4 Go → 8 Go, swappiness 60 → 10 |
| 2 | Allègement JVM Komga + StirlingPDF | Appliqué | Komga −292 Mio (−41 %), Stirling borné à 2 Go |
| 3 | OCR StirlingPDF impossible sur PNG | Résolu | Cause trouvée + script de contournement |
| 4 | Connexion Claude Code sur le VPS Alteris | Résolu | Identifiants recopiés depuis le VPS Jux |
1. Swap saturé — le vrai diagnostic
Symptôme
Swap à 3,8 / 4,0 Go (95 %), alors que ~4,6 Gi de RAM restaient disponibles. Il se remplissait nuit après nuit et ne se vidait jamais.
Ce que ce n'était PAS
Un manque de mémoire. vmstat 2 3 montrait si/so ≈ 0 : aucun thrashing, rien ne ramait.
C'est le point contre-intuitif de ce diagnostic — un swap plein n'est pas synonyme de machine à genoux.
Le risque réel était ailleurs : il ne restait que 253 Mio de swap libre. En cas de pic, l'OOM killer aurait commencé à tuer des containers.
Cause
vm.swappiness = 60 (valeur par défaut). Pendant les batchs de nuit — backup 2h, scan Komga 4h
(230 lignes de scan cette nuit-là), scans Audiobookshelf 4h et Navidrome 4h30 — le noyau préférait
pousser les pages anonymes des applications vers le swap plutôt que de réclamer son cache de pages.
Une fois en swap, ces pages n'en ressortent jamais d'elles-mêmes : elles n'y reviennent que si le processus les retouche. D'où une accumulation qui ne fait que croître, nuit après nuit.
Fixes appliqués
a) vm.swappiness = 10, persisté dans /etc/sysctl.d/99-swap.conf. Le noyau réclame désormais
son cache de pages avant de swapper. C'est ce qui empêche l'accumulation de recommencer.
b) Second fichier de swap /swapfile2 de 4 Go → swap total 8 Go, persisté dans /etc/fstab
(sauvegarde : /etc/fstab.bak-260803), validé par sudo swapon -a pour garantir un redémarrage sûr.
Méthode choisie délibérément : ajouter un second fichier évite tout swapoff, donc tout risque.
Un swapoff -a aurait dû recharger 3,8 Go dans 4,6 Go disponibles — faisable mais serré, plusieurs
minutes d'I/O intense, et un pic pendant l'opération aurait pu faire tuer un container.
État après intervention
| Avant | Après | |
|---|---|---|
| Swap total | 4,0 Go | 8,0 Go |
| Swap libre | 253 Mio | 4,2 Go |
vm.swappiness |
60 | 10 |
| Disque libre | 39 Go | 35 Go |
Ce qui reste
Les 3,8 Go de pages froides restent en swap. C'est assumé : elles ne coûtent rien en performance
et se libéreront au fil des redémarrages. Un docker restart libère instantanément le swap du
container concerné.
Top détenteurs au 2026-08-03 : komga 954 Mio, yourls-db 389, stirling-pdf 354, Immich-SERVER 212, Immich-DB 197, mealie 189, Kavita 158, jellyfin 131.
Le redémarrage de Komga rendra donc presque un giga à lui seul.
Commandes de diagnostic
swapon --show # taille et occupation de chaque zone
vmstat 2 3 # si/so : y a-t-il un swap ACTIF ?
cat /proc/sys/vm/swappiness
Swap par container :
cat /sys/fs/cgroup/system.slice/docker-$(docker inspect NOM --format '{{.Id}}').scope/memory.swap.current
Swap par processus :
for p in /proc/[0-9]*; do s=$(awk '/^VmSwap:/{print $2}' $p/status 2>/dev/null); \
[ -n "$s" ] && [ "$s" -gt 0 ] && echo "$s $(tr -d '\0' < $p/cmdline | cut -c1-60)"; done | sort -rn | head
À surveiller
Le lendemain matin, après une nuit de batchs : si le swap utilisé a peu bougé, swappiness=10 a fait
son travail. S'il remonte malgré tout, la piste suivante est de réduire les consommateurs réels
plutôt que de rejouer sur les réglages noyau.
2. Allègement JVM Komga + StirlingPDF
Appliqué le 2026-08-02 à 22h, après vérification du backup quotidien (BILAN 5/5 OK).
| Service | Avant | Après | Résultat |
|---|---|---|---|
| Komga (stack 7) | -Xmx4g -Xms2g -XX:MaxRAMPercentage=70.0, limits 4500M / reservations 3000M, 707 Mio |
-Xmx1g, limits 1500M / reservations 256M |
415 Mio (−292, −41 %) |
| StirlingPDF (stack 89) | JVM sans limite, 722 Mio | -Xmx512m, limits 2g |
785 Mio — pas de réduction |
Bilan hôte : swap 3,7 → 2,2 Go juste après l'opération, mémoire disponible 4,4 → 4,6 Gi.
L'essentiel du gain vient de Komga : c'est le -Xms2g qui pré-allouait 2 Go de heap au démarrage.
Pourquoi StirlingPDF ne baisse pas
À dire franchement plutôt que de maquiller le résultat : le process java conserve 799 Mio de RSS
malgré -Xmx512m. Le heap n'est qu'une partie du total (metaspace, code cache, piles de threads),
et Stirling lance en plus LibreOffice (soffice.bin, ~98 Mio), unoserver et Xvfb pour ses conversions.
Le bénéfice obtenu n'est pas une baisse mais un plafond : la consommation ne peut plus déborder, alors qu'elle était non bornée.
La limite portée de 1 Go à 2 Go — décision critique
Le plan initial prévoyait 1 Go. Il a été corrigé avant application, grâce au chantier OCR mené le
même jour : l'OCR fait tourner ocrmypdf et tesseract comme processus Python, hors JVM. -Xmx ne
les borne pas — seul le plafond cgroup du container s'applique.
Pic mesuré : 894 à 969 Mio pour une seule page A4 300 dpi. Un plafond de 1 Go aurait provoqué un
OOM kill dès le premier OCR. La version 1 Go est conservée en
/home/debian/stirling-compose-new.yml.orig1g mais ne doit pas être utilisée.
Vérifications après déploiement
- Komga répond 200, API
/api/v1/librariesrenvoie bien les bibliothèques - StirlingPDF :
compress-pdfOK (workflows komga-pdf et nas_geo_compress) et OCR OK (page A4 300 dpi, pic 969 Mio, aucun OOM kill, aucun redémarrage)
Piège de déploiement
Les projets compose s'appellent 7 et 89 — les IDs de stack Portainer — et non komga /
stirlingpdf. La procédure documentée initialement aurait échoué dessus.
sudo docker compose -p 7 -f /var/lib/docker/volumes/portainer_data/_data/compose/7/docker-compose.yml up -d
3. OCR StirlingPDF impossible sur les images PNG
Symptôme
HTTP 500 sur tout OCR d'image PNG. L'interface web n'affiche aucun détail exploitable — le
diagnostic passe obligatoirement par docker logs stirling-pdf.
Deux refus cumulés d'ocrmypdf 17.4.0
UnsupportedImageFormatError: The input image has an alpha channel.— tout PNG avec transparence- Une fois l'alpha retiré, un second blocage apparaît :
DpiError: Input file is an image, but has no resolution (DPI) in its metadata.StirlingPDF ne transmet pas--image-dpià ocrmypdf
Le point à retenir : les erreurs sont séquentielles. Corriger la transparence seule ne suffit pas, le DPI bloque juste après — ce qui explique pourquoi aucun réglage de l'interface ne pouvait s'en sortir.
Solution sans outil (interface web)
Convert → Image to PDF, puis OCR sur le PDF obtenu. Les deux problèmes disparaissent puisque l'entrée n'est plus une image. Validé en test, HTTP 200.
Solution scriptée
Jux-scripts/Stirling-OCR/ocr_image.py — aplatit l'alpha sur fond blanc et force 300 dpi avant envoi.
py "D:\Syncthing\Jux_univers\Jux-scripts\Stirling-OCR\ocr_image.py" mon_image.png
Accepte un fichier ou un dossier. Options : -l fra+eng, -o sortie.pdf, --dpi 400, --skip-text.
Testé depuis le PC Windows et depuis le VPS ; texte restitué à l'identique.
Chemin sur le VPS : /home/debian/Documents/Jux_univers/Jux-scripts/ (et non ~/Syncthing/...).
Détails techniques
- Endpoint :
POST /api/v1/misc/ocr-pdf— multipartfileInput, champslanguages(liste),ocrType(Force-OCR/skip-text),outputType - Langues tesseract installées (6) :
fra,eng,deu,por,chi_sim,osd - Versions : ocrmypdf 17.4.0, tesseract 5.3.4
4. Connexion Claude Code sur le VPS Alteris
Symptôme
Au lancement de claude en SSH (PuTTY / CMD / PowerShell), Claude Code demande de se connecter et
affiche une URL. Impossible de la copier : Ctrl+C, clic droit, rien ne fonctionnait. La mention
verte « copied » s'affichait pourtant.
Cause
Le « copied » venait de Claude Code tournant sur le VPS : il copiait l'URL dans le presse-papier du serveur Linux, qui n'a aucun lien avec celui du PC Windows à travers SSH. Le presse-papier Windows restait donc vide, d'où le collage à blanc dans le navigateur.
À noter au passage : dans un terminal SSH, Ctrl+C envoie un signal d'interruption au programme —
il peut tuer le processus de login au lieu de copier.
Cause réelle du re-login
Le fichier ~/.claude/.credentials.json d'Alteris avait expiresAt: 0 — jeton invalide.
Le VPS Jux, lui, disposait d'identifiants sains (compte Pro, refresh token valide).
Solution retenue
Recopier les identifiants depuis le VPS Jux, commande lancée depuis Alteris :
scp debian@51.77.141.54:.claude/.credentials.json ~/.claude/.credentials.json && chmod 600 ~/.claude/.credentials.json
Vérifié : 504 octets, permissions 600, jeton complet. Claude Code ne redemande plus de login et rafraîchit le token seul au démarrage (l'access token expiré n'est pas un problème, le refresh token est valide).
Conséquence : les deux VPS partagent désormais le même jeu d'identifiants. Si l'un redemande un
login, refaire le même scp depuis celui qui fonctionne encore.
Alternative si les deux tombent : claude setup-token depuis le PC Windows (le navigateur s'ouvre en
local), puis export CLAUDE_CODE_OAUTH_TOKEN=... dans le ~/.bashrc du serveur.
5. Découverte annexe — port PostgreSQL 5432 bloqué sur Alteris
publier_recherche.py échoue sur sa partie PostgreSQL : Connection timed out (10060).
- ufw est actif sur Alteris sans règle pour 5432
- Le container
alteris_postgistourne etpg_isreadyrépond en local - Vérifié : le port est injoignable depuis le PC et depuis le VPS Jux
Contournement sans toucher au pare-feu — exécuter le SQL en local sur Alteris :
pscp fichier.sql debian@79.137.14.202:/tmp/
sudo docker cp /tmp/fichier.sql alteris_postgis:/tmp/i.sql
sudo docker exec alteris_postgis psql -U alteris_admin -d alteris_geo -f /tmp/i.sql
Rouvrir le port exposerait à nouveau une base de données directement sur internet. Décision à prendre sciemment, surtout après l'incident du 2026-06-09.
Fichiers, sauvegardes et rollbacks
| Élément | Chemin | Rôle |
|---|---|---|
| Compose Komga (avant) | /var/lib/docker/volumes/portainer_data/_data/compose/7/docker-compose.yml.bak-260802 |
Rollback Komga |
| Compose Stirling (avant) | /var/lib/docker/volumes/portainer_data/_data/compose/89/docker-compose.yml.bak-260802 |
Rollback Stirling |
| Version Stirling 1 Go | /home/debian/stirling-compose-new.yml.orig1g |
Ne pas utiliser (OOM sur OCR) |
| fstab (avant) | /etc/fstab.bak-260803 |
Rollback swap |
| Réglage swappiness | /etc/sysctl.d/99-swap.conf |
vm.swappiness = 10 |
| Second swap | /swapfile2 (4 Go) |
Marge de swap |
| Script OCR | Jux-scripts/Stirling-OCR/ocr_image.py + README.md |
Contournement OCR images |
Rollback JVM : restaurer le .bak-260802 de la stack et redéployer avec
sudo docker compose -p {7|89} -f ... up -d.
Références
- Page 177 — 00_Récapitulatif : section « 260802 - Allègement JVM Komga + StirlingPDF »
- Page 211 — REX StirlingPDF : entrée
RCH-20260802-0001(également en baserecherchessur Alteris) - Page 208 — 25_StirlingPDF
CLAUDE.mddu projet : sections « Swap », « Alléger Komga », « Alléger StirlingPDF », StirlingPDF/OCR
01_Les recherches de Claude
Pages de publication des résultats d'analyse et de production de Claude Code sur le contenu du VPS
01A_Kdrive_les explorations
RCH-20260529-0003 — Livres et ressources evoquant la ville de Genes dans Foxy
| Date | 2026-05-29 |
|---|---|
| Service | kDrive Infomaniak |
| Contexte | Constituer un corpus documentaire autour de Genes (Genovese, Ligurie) dans la bibliotheque kDrive — dossier SYNC-pour_VPS/Sync_NAS-Maison/Foxy |
| Outils utilisés | API REST Infomaniak kDrive v3 — search + metadata v2 | PowerShell |
| Requête | GET /3/drive/591617/files/search?query={Genes|Genova|Genovese|Genoa|Ligurie}&limit=20 | filtre manuel sur résultats |
Résultats
3 livres directement sur Gênes (la ville), 1 presentation Ligurie, des photos de Ligurie (2011), et des recettes genovese (cuisine). Recherche couvrant les termes : Genes, Genova, Genovese, Genoa, Ligurie.
Points clés
- 3 livres historiques sur Gênes trouvés : Graziani (5.2 MB), Vincens (0.9 MB), Histoire anonyme (0.8 MB)
- 1 présentation PowerPoint Ligurie (31.9 MB, mai 2021) — probablement riche en images et contenu
- Photos de Ligurie 2011 (Ognelia et Imperia) — 20+ photos personnelles
- Ressources culinaires genovese : Focaccia Genovese, Ravioli alla genovese (videos kDrive)
- Les livres sont dans Foxy (ID:401926) — dossier probable : Histoire ou Culture Italie
- L'API search kDrive retourne des faux positifs (Genèse, Gens, Genève) — filtrage manuel nécessaire
Limites
L'API v2 ne retourne pas le chemin (path) des fichiers — impossible de localiser précisément le sous-dossier sans navigation manuelle. Le champ path est vide dans la réponse.
Localisation des ressources
| URLs | — |
|---|---|
| Chemins | ["kDrive 591617 / Private (5) / SYNC-pour_VPS (534292) / Sync_NAS-Maison (534293) / Foxy (401926) / [sous-dossier inconnu]"] |
| IDs | {"531552": "Antoine-Marie Graziani - Histoire de Genes.epub (5.2 MB)", "531550": "Histoire de de Genes - Histoire.epub (0.8 MB)", "531549": "Histoire de la République de Gênes - Emile Vincens - Histoire.epub (0.9 MB)", "501392": "210526-Ligurie.pptx (31.9 MB)"} |
| Auteurs / Source | ["Antoine-Marie Graziani (Histoire de Genes)", "Emile Vincens (Histoire de la République de Gênes)"] |
| Métadonnées | {"formats": ["epub", "pptx", "jpg", "mp4"], "livres_genes": 3, "photos_ligurie": 20, "videos_recettes_genovese": 2, "dossier_foxy_id": 401926, "kdrive_id": 591617} |
Tags
#Genes #Gênes #Ligurie #Italie #histoire #kDrive #epub #bibliotheque
Suite / Pistes
1/ Explorer le dossier Culture Italie (ID:1185062) pour trouver d'autres ressources sur Genes. 2/ Verifier dans Calibre (ID:1211295) si des livres Genes y sont catalogues. 3/ Corriger l'API v2 pour obtenir le chemin des fichiers (utiliser /3/ au lieu de /2/). 4/ Croiser avec Kavita si ces epubs y sont importes.
RCH-20260529-0004 — Approfondissement corpus Gênes — Culture Italie et Bibliotheque Calibre
| Date | 2026-05-29 |
|---|---|
| Service | kDrive Infomaniak |
| Contexte | Suite de RCH-20260529-0003. Explorer Culture Italie (ID:1185062) et Bibliotheque Calibre (ID:1211295) pour compléter le corpus #Genes. |
| Outils utilisés | API REST kDrive v3 — navigation par ID + listing sous-dossiers | PowerShell |
| Requête | GET /3/drive/591617/files/{1185194|1185151|1185105|1185085|1211295}/files?limit=100 + filtres regex Genes/Ligurie |
Résultats
Culture Italie contient un dossier Ligurie (Cuisine Italie/Ligurie) avec 2 fichiers. Calibre contient Graziani mais uniquement pour Pascal Paoli (Corse), pas Genes. Vincens absent de Calibre. Plusieurs livres sur l'Italie générale potentiellement exploitables.
Points clés
- Dossier Ligurie trouvé dans Cuisine Italie (ID:1185345) : PPTX 31.9MB + IMG_3782.pdf
- Calibre/Graziani (ID:1362307) = Pascal Paoli uniquement — Histoire de Genes est dans Foxy seulement
- Vincens (Histoire de la République de Gênes) absent de Calibre — epub uniquement dans Foxy
- Culture Italie / Art de vivre : 5 ressources générales sur l'Italie (Bella Italia, Continent Italia, Sacrés Italiens, Portraits d'Italie, Geo Dolce Vita)
- Histoire Italie : Les guerres d'Italie (conflit européen) — contexte historique pertinent pour Gênes
- Le corpus Gênes dans kDrive est concentré dans Foxy/Histoire — Calibre ne l'a pas indexé
Limites
Calibre n'a pas les livres sur Gênes de Vincens et de la version anonyme. Seul Graziani y est mais pour un autre ouvrage. Les 3 epubs Genes sont uniquement dans Foxy, non indexés dans Calibre. La recherche ne couvre pas les sous-sous-dossiers de Calibre (trop nombreux).
Localisation des ressources
| URLs | — |
|---|---|
| Chemins | ["Foxy/Culture Italie/Cuisine Italie/Ligurie", "Foxy/Culture Italie/Histoire Italie", "Foxy/Culture Italie/Art de vivre Italie", "Foxy/Bibliotheque Calibre/Antoine-Marie Graziani"] |
| IDs | {"1185345": "Dossier Ligurie dans Cuisine Italie", "1185347": "210526-Ligurie.pptx (31.9 MB) — dans Cuisine Italie/Ligurie", "1185349": "IMG_3782.pdf — dans Cuisine Italie/Ligurie", "1362307": "Calibre/Antoine-Marie Graziani (Pascal Paoli — pas Gênes)", "1185194": "Histoire Italie (4 livres generaux)", "1185085": "Art de vivre Italie (5 ressources)", "1185201": "L'Italie de Botticelli à Bonaparte.epub", "1185199": "Les guerres d'Italie — Un conflit européen.epub", "1185196": "Bella Italia - Un itinéraire amoureux (Christiane Rance).epub", "1185090": "Sacrés Italiens (Alberto Toscano).epub", "1185089": "Portraits d'Italie (Laurent Bolard).epub", "1185087": "Geo Hors-Serie Dolce Vita Avril-Mai 2025.pdf"} |
| Auteurs / Source | — |
| Métadonnées | {"corpus_genes_directs": 3, "ressources_ligurie": 2, "livres_italie_generale": 9, "calibre_graziani_titre": "Pascal Paoli - Pere de la patrie corse", "vincens_dans_calibre": false} |
Tags
#Genes #Genes #Ligurie #Italie #Calibre #kDrive #Culture Italie #histoire
Suite / Pistes
1/ Importer les 3 epubs Genes (IDs 531549-531552) dans Calibre pour les indexer. 2/ Lire le PPTX Ligurie (ID:1185347) pour en extraire le contenu. 3/ Explorer 'Bella Italia' et 'Les guerres d'Italie' pour mentions de Genes. 4/ Rechercher 'Genes' dans le dossier Histoire (ID:503138) de Foxy.
01_Portainer - les explorations
Journal des recherches réalisées avec Claude Code sur le service Portainer.
Documentation technique : https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/152
Chaque entrée est automatiquement enregistrée dans la table recherches (PostgreSQL Alteris, DB 35 Metabase).
RCH-AAAAMMJJ-NNNN — [Objet de la recherche]
| Date | AAAA-MM-JJ |
|---|---|
| Service | [nom du service] |
| Contexte | [Pourquoi cette recherche — quelle question, quel besoin, quel problème] |
| Outils utilisés | [MCP utilisé / API directe / PowerShell / Python / recherche web...] |
| Requête | [query exacte, paramètres, filtres, commandes] |
Résultats
[Description des résultats obtenus — texte libre, liste, tableau selon le volume]
Points clés
- [Insight 1 — ce qui est important ou surprenant]
- [Insight 2]
- [Insight 3]
Limites
[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties]
Localisation des ressources
| URLs | [liens directs vers les ressources trouvées] |
|---|---|
| Chemins | [chemins fichiers, répertoires, arborescences] |
| IDs | [IDs containers, pages, assets, items...] |
| Auteurs / Source | [auteurs, éditeurs, provenance] |
| Métadonnées | [dates, formats, tailles, langues, coordonnées...] |
Tags
#tag1 #tag2 #tag3
Suite / Pistes
[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer]
02_Bookstack_les explorations
Journal des recherches réalisées avec Claude Code sur le service Bookstack.
Documentation technique : https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/153
Chaque entrée est automatiquement enregistrée dans la table recherches (PostgreSQL Alteris, DB 35 Metabase).
RCH-AAAAMMJJ-NNNN — [Objet de la recherche]
| Date | AAAA-MM-JJ |
|---|---|
| Service | [nom du service] |
| Contexte | [Pourquoi cette recherche — quelle question, quel besoin, quel problème] |
| Outils utilisés | [MCP utilisé / API directe / PowerShell / Python / recherche web...] |
| Requête | [query exacte, paramètres, filtres, commandes] |
Résultats
[Description des résultats obtenus — texte libre, liste, tableau selon le volume]
Points clés
- [Insight 1 — ce qui est important ou surprenant]
- [Insight 2]
- [Insight 3]
Limites
[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties]
Localisation des ressources
| URLs | [liens directs vers les ressources trouvées] |
|---|---|
| Chemins | [chemins fichiers, répertoires, arborescences] |
| IDs | [IDs containers, pages, assets, items...] |
| Auteurs / Source | [auteurs, éditeurs, provenance] |
| Métadonnées | [dates, formats, tailles, langues, coordonnées...] |
Tags
#tag1 #tag2 #tag3
Suite / Pistes
[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer]
03_Homarr_les explorations
Journal des recherches réalisées avec Claude Code sur le service Homarr.
Documentation technique : https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/154
Chaque entrée est automatiquement enregistrée dans la table recherches (PostgreSQL Alteris, DB 35 Metabase).
RCH-AAAAMMJJ-NNNN — [Objet de la recherche]
| Date | AAAA-MM-JJ |
|---|---|
| Service | [nom du service] |
| Contexte | [Pourquoi cette recherche — quelle question, quel besoin, quel problème] |
| Outils utilisés | [MCP utilisé / API directe / PowerShell / Python / recherche web...] |
| Requête | [query exacte, paramètres, filtres, commandes] |
Résultats
[Description des résultats obtenus — texte libre, liste, tableau selon le volume]
Points clés
- [Insight 1 — ce qui est important ou surprenant]
- [Insight 2]
- [Insight 3]
Limites
[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties]
Localisation des ressources
| URLs | [liens directs vers les ressources trouvées] |
|---|---|
| Chemins | [chemins fichiers, répertoires, arborescences] |
| IDs | [IDs containers, pages, assets, items...] |
| Auteurs / Source | [auteurs, éditeurs, provenance] |
| Métadonnées | [dates, formats, tailles, langues, coordonnées...] |
Tags
#tag1 #tag2 #tag3
Suite / Pistes
[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer]
04_Audiobookshelf_les explorations
Journal des recherches réalisées avec Claude Code sur le service Audiobookshelf.
Documentation technique : https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/155
Chaque entrée est automatiquement enregistrée dans la table recherches (PostgreSQL Alteris, DB 35 Metabase).
RCH-AAAAMMJJ-NNNN — [Objet de la recherche]
| Date | AAAA-MM-JJ |
|---|---|
| Service | [nom du service] |
| Contexte | [Pourquoi cette recherche — quelle question, quel besoin, quel problème] |
| Outils utilisés | [MCP utilisé / API directe / PowerShell / Python / recherche web...] |
| Requête | [query exacte, paramètres, filtres, commandes] |
Résultats
[Description des résultats obtenus — texte libre, liste, tableau selon le volume]
Points clés
- [Insight 1 — ce qui est important ou surprenant]
- [Insight 2]
- [Insight 3]
Limites
[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties]
Localisation des ressources
| URLs | [liens directs vers les ressources trouvées] |
|---|---|
| Chemins | [chemins fichiers, répertoires, arborescences] |
| IDs | [IDs containers, pages, assets, items...] |
| Auteurs / Source | [auteurs, éditeurs, provenance] |
| Métadonnées | [dates, formats, tailles, langues, coordonnées...] |
Tags
#tag1 #tag2 #tag3
Suite / Pistes
[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer]
05_BentoPDF_les explorations
Journal des recherches réalisées avec Claude Code sur le service BentoPDF.
Documentation technique : https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/156
Chaque entrée est automatiquement enregistrée dans la table recherches (PostgreSQL Alteris, DB 35 Metabase).
RCH-AAAAMMJJ-NNNN — [Objet de la recherche]
| Date | AAAA-MM-JJ |
|---|---|
| Service | [nom du service] |
| Contexte | [Pourquoi cette recherche — quelle question, quel besoin, quel problème] |
| Outils utilisés | [MCP utilisé / API directe / PowerShell / Python / recherche web...] |
| Requête | [query exacte, paramètres, filtres, commandes] |
Résultats
[Description des résultats obtenus — texte libre, liste, tableau selon le volume]
Points clés
- [Insight 1 — ce qui est important ou surprenant]
- [Insight 2]
- [Insight 3]
Limites
[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties]
Localisation des ressources
| URLs | [liens directs vers les ressources trouvées] |
|---|---|
| Chemins | [chemins fichiers, répertoires, arborescences] |
| IDs | [IDs containers, pages, assets, items...] |
| Auteurs / Source | [auteurs, éditeurs, provenance] |
| Métadonnées | [dates, formats, tailles, langues, coordonnées...] |
Tags
#tag1 #tag2 #tag3
Suite / Pistes
[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer]
06_Cadvisor_les explorations
Journal des recherches réalisées avec Claude Code sur le service Cadvisor.
Documentation technique : https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/157
Chaque entrée est automatiquement enregistrée dans la table recherches (PostgreSQL Alteris, DB 35 Metabase).
RCH-AAAAMMJJ-NNNN — [Objet de la recherche]
| Date | AAAA-MM-JJ |
|---|---|
| Service | [nom du service] |
| Contexte | [Pourquoi cette recherche — quelle question, quel besoin, quel problème] |
| Outils utilisés | [MCP utilisé / API directe / PowerShell / Python / recherche web...] |
| Requête | [query exacte, paramètres, filtres, commandes] |
Résultats
[Description des résultats obtenus — texte libre, liste, tableau selon le volume]
Points clés
- [Insight 1 — ce qui est important ou surprenant]
- [Insight 2]
- [Insight 3]
Limites
[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties]
Localisation des ressources
| URLs | [liens directs vers les ressources trouvées] |
|---|---|
| Chemins | [chemins fichiers, répertoires, arborescences] |
| IDs | [IDs containers, pages, assets, items...] |
| Auteurs / Source | [auteurs, éditeurs, provenance] |
| Métadonnées | [dates, formats, tailles, langues, coordonnées...] |
Tags
#tag1 #tag2 #tag3
Suite / Pistes
[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer]
07_Calibre-web_les explorations
Journal des recherches réalisées avec Claude Code sur le service Calibre-web.
Documentation technique : https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/158
Chaque entrée est automatiquement enregistrée dans la table recherches (PostgreSQL Alteris, DB 35 Metabase).
RCH-AAAAMMJJ-NNNN — [Objet de la recherche]
| Date | AAAA-MM-JJ |
|---|---|
| Service | [nom du service] |
| Contexte | [Pourquoi cette recherche — quelle question, quel besoin, quel problème] |
| Outils utilisés | [MCP utilisé / API directe / PowerShell / Python / recherche web...] |
| Requête | [query exacte, paramètres, filtres, commandes] |
Résultats
[Description des résultats obtenus — texte libre, liste, tableau selon le volume]
Points clés
- [Insight 1 — ce qui est important ou surprenant]
- [Insight 2]
- [Insight 3]
Limites
[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties]
Localisation des ressources
| URLs | [liens directs vers les ressources trouvées] |
|---|---|
| Chemins | [chemins fichiers, répertoires, arborescences] |
| IDs | [IDs containers, pages, assets, items...] |
| Auteurs / Source | [auteurs, éditeurs, provenance] |
| Métadonnées | [dates, formats, tailles, langues, coordonnées...] |
Tags
#tag1 #tag2 #tag3
Suite / Pistes
[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer]
08_Dozzle_les explorations
Journal des recherches réalisées avec Claude Code sur le service Dozzle.
Documentation technique : https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/159
Chaque entrée est automatiquement enregistrée dans la table recherches (PostgreSQL Alteris, DB 35 Metabase).
RCH-AAAAMMJJ-NNNN — [Objet de la recherche]
| Date | AAAA-MM-JJ |
|---|---|
| Service | [nom du service] |
| Contexte | [Pourquoi cette recherche — quelle question, quel besoin, quel problème] |
| Outils utilisés | [MCP utilisé / API directe / PowerShell / Python / recherche web...] |
| Requête | [query exacte, paramètres, filtres, commandes] |
Résultats
[Description des résultats obtenus — texte libre, liste, tableau selon le volume]
Points clés
- [Insight 1 — ce qui est important ou surprenant]
- [Insight 2]
- [Insight 3]
Limites
[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties]
Localisation des ressources
| URLs | [liens directs vers les ressources trouvées] |
|---|---|
| Chemins | [chemins fichiers, répertoires, arborescences] |
| IDs | [IDs containers, pages, assets, items...] |
| Auteurs / Source | [auteurs, éditeurs, provenance] |
| Métadonnées | [dates, formats, tailles, langues, coordonnées...] |
Tags
#tag1 #tag2 #tag3
Suite / Pistes
[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer]
09_FileBrowser_les explorations
Journal des recherches réalisées avec Claude Code sur le service FileBrowser.
Documentation technique : https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/160
Chaque entrée est automatiquement enregistrée dans la table recherches (PostgreSQL Alteris, DB 35 Metabase).
RCH-AAAAMMJJ-NNNN — [Objet de la recherche]
| Date | AAAA-MM-JJ |
|---|---|
| Service | [nom du service] |
| Contexte | [Pourquoi cette recherche — quelle question, quel besoin, quel problème] |
| Outils utilisés | [MCP utilisé / API directe / PowerShell / Python / recherche web...] |
| Requête | [query exacte, paramètres, filtres, commandes] |
Résultats
[Description des résultats obtenus — texte libre, liste, tableau selon le volume]
Points clés
- [Insight 1 — ce qui est important ou surprenant]
- [Insight 2]
- [Insight 3]
Limites
[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties]
Localisation des ressources
| URLs | [liens directs vers les ressources trouvées] |
|---|---|
| Chemins | [chemins fichiers, répertoires, arborescences] |
| IDs | [IDs containers, pages, assets, items...] |
| Auteurs / Source | [auteurs, éditeurs, provenance] |
| Métadonnées | [dates, formats, tailles, langues, coordonnées...] |
Tags
#tag1 #tag2 #tag3
Suite / Pistes
[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer]
10_FreshRSS_les explorations
RCH-20260529-0002 — Articles Inkscape dans la categorie claude_foss
| Date | 2026-05-29 |
|---|---|
| Service | FreshRSS |
| Contexte | Second passage apres creation de la categorie claude_foss et ajout du flux Inkscape News. Verifier si des articles sur Inkscape sont desormais indexes. |
| Outils utilisés | API GReader FreshRSS directe — stream/contents/user/-/label/claude_foss — search_foss.py |
| Requête | GET /reader/api/0/stream/contents/user/-/label/claude_foss?n=100&q=Inkscape |
Résultats
100 articles retournes depuis la categorie claude_foss (7 flux). 10 articles provenant du flux Inkscape News (feed/615) sont presents. Note : le parametre q= de l'API GReader ne filtre pas reellement par mot-cle — il retourne tous les articles du stream. Le filtrage Inkscape est donc a faire cote client.
Points clés
- 10 articles Inkscape indexés depuis l'ajout du flux feed/615 (inkscape.org/news)
- Dernière release : Inkscape 1.4.4 (2026-05-06) — ameliorations performances et corrections crashes
- Inkscape soutient une pétition allemande pour la reconnaissance des bénévoles Open Source (2026-05-13)
- Interview artiste : court-métrage animé réalisé entièrement sous Inkscape (2026-04-02)
- L'API GReader q= ne filtre pas par mot-clé : retourne tous les articles du stream — filtrage client nécessaire
- Flux claude_foss opérationnel : 7 sources (Inkscape, LinuxFr, Planet GNOME, Blender, LibreOffice, Libre Arts)
Limites
Le parametre q= de l'API GReader FreshRSS ne filtre pas par mot-cle. Pour une recherche thematique precise, il faut recuperer tous les articles et filtrer cote client sur title + content. A corriger dans search_foss.py.
Localisation des ressources
| URLs | ["https://inkscape.org/news/2026/05/13/inkscape-supports-german-petition-to-recognize-ope/", "https://inkscape.org/news/2026/05/06/inkscape-144-boosts-performance-and-crushes-crashe/", "https://inkscape.org/news/2026/04/02/artist-interview-meet-jorge-who-made-a-short-film/", "https://inkscape.org/news/2026/03/02/inkscape-is-hiring-2026-1/", "https://inkscape.org/news/2025/12/26/bugs-banished-inkscape-143-is-out/", "https://inkscape.org/news/2025/10/12/indiafoss-2025/", "https://inkscape.org/news/2025/06/08/libre-graphics-meeting-2025/", "https://inkscape.org/news/2025/06/01/inkscape-summit-nuremberg/", "https://inkscape.org/news/2025/05/12/2-in-1-release-inkscape-142-is-out/", "https://inkscape.org/news/2025/02/05/inkscape-summit-frankfurt-2025/"] |
|---|---|
| Chemins | — |
| IDs | ["feed/615 (Inkscape News)", "user/-/label/claude_foss"] |
| Auteurs / Source | ["Inkscape Project"] |
| Métadonnées | {"articles_inkscape": 10, "articles_total_stream": 100, "flux_claude_foss": 7, "derniere_version": "Inkscape 1.4.4", "date_derniere_version": "2026-05-06", "periode_couverte": "2025-02 a 2026-05"} |
Tags
#Inkscape #logiciel-libre #SVG #dessin-vectoriel #FOSS #FreshRSS #claude_foss
Suite / Pistes
1/ Corriger search_foss.py pour filtrer cote client sur title+content. 2/ Ajouter flux Libre Graphics Meeting et Planet Inkscape si existants. 3/ Relancer apres quelques jours pour capter les nouveaux articles. 4/ Croiser avec Kavita (livres SVG/Inkscape) et kDrive (tutoriels eventuels).
11_Gitea_les explorations
Journal des recherches réalisées avec Claude Code sur le service Gitea.
Documentation technique : https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/162
Chaque entrée est automatiquement enregistrée dans la table recherches (PostgreSQL Alteris, DB 35 Metabase).
RCH-AAAAMMJJ-NNNN — [Objet de la recherche]
| Date | AAAA-MM-JJ |
|---|---|
| Service | [nom du service] |
| Contexte | [Pourquoi cette recherche — quelle question, quel besoin, quel problème] |
| Outils utilisés | [MCP utilisé / API directe / PowerShell / Python / recherche web...] |
| Requête | [query exacte, paramètres, filtres, commandes] |
Résultats
[Description des résultats obtenus — texte libre, liste, tableau selon le volume]
Points clés
- [Insight 1 — ce qui est important ou surprenant]
- [Insight 2]
- [Insight 3]
Limites
[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties]
Localisation des ressources
| URLs | [liens directs vers les ressources trouvées] |
|---|---|
| Chemins | [chemins fichiers, répertoires, arborescences] |
| IDs | [IDs containers, pages, assets, items...] |
| Auteurs / Source | [auteurs, éditeurs, provenance] |
| Métadonnées | [dates, formats, tailles, langues, coordonnées...] |
Tags
#tag1 #tag2 #tag3
Suite / Pistes
[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer]
12_Grafana_les explorations
Journal des recherches réalisées avec Claude Code sur le service Grafana.
Documentation technique : https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/163
Chaque entrée est automatiquement enregistrée dans la table recherches (PostgreSQL Alteris, DB 35 Metabase).
RCH-AAAAMMJJ-NNNN — [Objet de la recherche]
| Date | AAAA-MM-JJ |
|---|---|
| Service | [nom du service] |
| Contexte | [Pourquoi cette recherche — quelle question, quel besoin, quel problème] |
| Outils utilisés | [MCP utilisé / API directe / PowerShell / Python / recherche web...] |
| Requête | [query exacte, paramètres, filtres, commandes] |
Résultats
[Description des résultats obtenus — texte libre, liste, tableau selon le volume]
Points clés
- [Insight 1 — ce qui est important ou surprenant]
- [Insight 2]
- [Insight 3]
Limites
[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties]
Localisation des ressources
| URLs | [liens directs vers les ressources trouvées] |
|---|---|
| Chemins | [chemins fichiers, répertoires, arborescences] |
| IDs | [IDs containers, pages, assets, items...] |
| Auteurs / Source | [auteurs, éditeurs, provenance] |
| Métadonnées | [dates, formats, tailles, langues, coordonnées...] |
Tags
#tag1 #tag2 #tag3
Suite / Pistes
[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer]
13_Immich_les explorations
Journal des recherches réalisées avec Claude Code sur le service Immich.
Documentation technique : https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/164
Chaque entrée est automatiquement enregistrée dans la table recherches (PostgreSQL Alteris, DB 35 Metabase).
RCH-AAAAMMJJ-NNNN — [Objet de la recherche]
| Date | AAAA-MM-JJ |
|---|---|
| Service | [nom du service] |
| Contexte | [Pourquoi cette recherche — quelle question, quel besoin, quel problème] |
| Outils utilisés | [MCP utilisé / API directe / PowerShell / Python / recherche web...] |
| Requête | [query exacte, paramètres, filtres, commandes] |
Résultats
[Description des résultats obtenus — texte libre, liste, tableau selon le volume]
Points clés
- [Insight 1 — ce qui est important ou surprenant]
- [Insight 2]
- [Insight 3]
Limites
[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties]
Localisation des ressources
| URLs | [liens directs vers les ressources trouvées] |
|---|---|
| Chemins | [chemins fichiers, répertoires, arborescences] |
| IDs | [IDs containers, pages, assets, items...] |
| Auteurs / Source | [auteurs, éditeurs, provenance] |
| Métadonnées | [dates, formats, tailles, langues, coordonnées...] |
Tags
#tag1 #tag2 #tag3
Suite / Pistes
[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer]
14_Jellyfin_les explorations
Journal des recherches réalisées avec Claude Code sur le service Jellyfin.
Documentation technique : https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/165
Chaque entrée est automatiquement enregistrée dans la table recherches (PostgreSQL Alteris, DB 35 Metabase).
RCH-AAAAMMJJ-NNNN — [Objet de la recherche]
| Date | AAAA-MM-JJ |
|---|---|
| Service | [nom du service] |
| Contexte | [Pourquoi cette recherche — quelle question, quel besoin, quel problème] |
| Outils utilisés | [MCP utilisé / API directe / PowerShell / Python / recherche web...] |
| Requête | [query exacte, paramètres, filtres, commandes] |
Résultats
[Description des résultats obtenus — texte libre, liste, tableau selon le volume]
Points clés
- [Insight 1 — ce qui est important ou surprenant]
- [Insight 2]
- [Insight 3]
Limites
[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties]
Localisation des ressources
| URLs | [liens directs vers les ressources trouvées] |
|---|---|
| Chemins | [chemins fichiers, répertoires, arborescences] |
| IDs | [IDs containers, pages, assets, items...] |
| Auteurs / Source | [auteurs, éditeurs, provenance] |
| Métadonnées | [dates, formats, tailles, langues, coordonnées...] |
Tags
#tag1 #tag2 #tag3
Suite / Pistes
[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer]
15_Joplin_les explorations
Journal des recherches réalisées avec Claude Code sur le service Joplin.
Documentation technique : https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/166
Chaque entrée est automatiquement enregistrée dans la table recherches (PostgreSQL Alteris, DB 35 Metabase).
RCH-AAAAMMJJ-NNNN — [Objet de la recherche]
| Date | AAAA-MM-JJ |
|---|---|
| Service | [nom du service] |
| Contexte | [Pourquoi cette recherche — quelle question, quel besoin, quel problème] |
| Outils utilisés | [MCP utilisé / API directe / PowerShell / Python / recherche web...] |
| Requête | [query exacte, paramètres, filtres, commandes] |
Résultats
[Description des résultats obtenus — texte libre, liste, tableau selon le volume]
Points clés
- [Insight 1 — ce qui est important ou surprenant]
- [Insight 2]
- [Insight 3]
Limites
[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties]
Localisation des ressources
| URLs | [liens directs vers les ressources trouvées] |
|---|---|
| Chemins | [chemins fichiers, répertoires, arborescences] |
| IDs | [IDs containers, pages, assets, items...] |
| Auteurs / Source | [auteurs, éditeurs, provenance] |
| Métadonnées | [dates, formats, tailles, langues, coordonnées...] |
Tags
#tag1 #tag2 #tag3
Suite / Pistes
[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer]
16_Kavita_les explorations
Journal des recherches réalisées avec Claude Code sur le service Kavita.
Documentation technique : https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/167
Chaque entrée est automatiquement enregistrée dans la table recherches (PostgreSQL Alteris, DB 35 Metabase).
RCH-AAAAMMJJ-NNNN — [Objet de la recherche]
| Date | AAAA-MM-JJ |
|---|---|
| Service | [nom du service] |
| Contexte | [Pourquoi cette recherche — quelle question, quel besoin, quel problème] |
| Outils utilisés | [MCP utilisé / API directe / PowerShell / Python / recherche web...] |
| Requête | [query exacte, paramètres, filtres, commandes] |
Résultats
[Description des résultats obtenus — texte libre, liste, tableau selon le volume]
Points clés
- [Insight 1 — ce qui est important ou surprenant]
- [Insight 2]
- [Insight 3]
Limites
[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties]
Localisation des ressources
| URLs | [liens directs vers les ressources trouvées] |
|---|---|
| Chemins | [chemins fichiers, répertoires, arborescences] |
| IDs | [IDs containers, pages, assets, items...] |
| Auteurs / Source | [auteurs, éditeurs, provenance] |
| Métadonnées | [dates, formats, tailles, langues, coordonnées...] |
Tags
#tag1 #tag2 #tag3
Suite / Pistes
[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer]
17_Komga_les explorations
Journal des recherches réalisées avec Claude Code sur le service Komga.
Documentation technique : https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/168
Chaque entrée est automatiquement enregistrée dans la table recherches (PostgreSQL Alteris, DB 35 Metabase).
RCH-AAAAMMJJ-NNNN — [Objet de la recherche]
| Date | AAAA-MM-JJ |
|---|---|
| Service | [nom du service] |
| Contexte | [Pourquoi cette recherche — quelle question, quel besoin, quel problème] |
| Outils utilisés | [MCP utilisé / API directe / PowerShell / Python / recherche web...] |
| Requête | [query exacte, paramètres, filtres, commandes] |
Résultats
[Description des résultats obtenus — texte libre, liste, tableau selon le volume]
Points clés
- [Insight 1 — ce qui est important ou surprenant]
- [Insight 2]
- [Insight 3]
Limites
[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties]
Localisation des ressources
| URLs | [liens directs vers les ressources trouvées] |
|---|---|
| Chemins | [chemins fichiers, répertoires, arborescences] |
| IDs | [IDs containers, pages, assets, items...] |
| Auteurs / Source | [auteurs, éditeurs, provenance] |
| Métadonnées | [dates, formats, tailles, langues, coordonnées...] |
Tags
#tag1 #tag2 #tag3
Suite / Pistes
[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer]
18_Mealie_les explorations
Journal des recherches réalisées avec Claude Code sur le service Mealie.
Documentation technique : https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/169
Chaque entrée est automatiquement enregistrée dans la table recherches (PostgreSQL Alteris, DB 35 Metabase).
RCH-AAAAMMJJ-NNNN — [Objet de la recherche]
| Date | AAAA-MM-JJ |
|---|---|
| Service | [nom du service] |
| Contexte | [Pourquoi cette recherche — quelle question, quel besoin, quel problème] |
| Outils utilisés | [MCP utilisé / API directe / PowerShell / Python / recherche web...] |
| Requête | [query exacte, paramètres, filtres, commandes] |
Résultats
[Description des résultats obtenus — texte libre, liste, tableau selon le volume]
Points clés
- [Insight 1 — ce qui est important ou surprenant]
- [Insight 2]
- [Insight 3]
Limites
[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties]
Localisation des ressources
| URLs | [liens directs vers les ressources trouvées] |
|---|---|
| Chemins | [chemins fichiers, répertoires, arborescences] |
| IDs | [IDs containers, pages, assets, items...] |
| Auteurs / Source | [auteurs, éditeurs, provenance] |
| Métadonnées | [dates, formats, tailles, langues, coordonnées...] |
Tags
#tag1 #tag2 #tag3
Suite / Pistes
[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer]
19_Navidrome_les explorations
Journal des recherches réalisées avec Claude Code sur le service Navidrome.
Documentation technique : https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/170
Chaque entrée est automatiquement enregistrée dans la table recherches (PostgreSQL Alteris, DB 35 Metabase).
RCH-AAAAMMJJ-NNNN — [Objet de la recherche]
| Date | AAAA-MM-JJ |
|---|---|
| Service | [nom du service] |
| Contexte | [Pourquoi cette recherche — quelle question, quel besoin, quel problème] |
| Outils utilisés | [MCP utilisé / API directe / PowerShell / Python / recherche web...] |
| Requête | [query exacte, paramètres, filtres, commandes] |
Résultats
[Description des résultats obtenus — texte libre, liste, tableau selon le volume]
Points clés
- [Insight 1 — ce qui est important ou surprenant]
- [Insight 2]
- [Insight 3]
Limites
[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties]
Localisation des ressources
| URLs | [liens directs vers les ressources trouvées] |
|---|---|
| Chemins | [chemins fichiers, répertoires, arborescences] |
| IDs | [IDs containers, pages, assets, items...] |
| Auteurs / Source | [auteurs, éditeurs, provenance] |
| Métadonnées | [dates, formats, tailles, langues, coordonnées...] |
Tags
#tag1 #tag2 #tag3
Suite / Pistes
[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer]
20_NodeExporter_les explorations
Journal des recherches réalisées avec Claude Code sur le service NodeExporter.
Documentation technique : https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/171
Chaque entrée est automatiquement enregistrée dans la table recherches (PostgreSQL Alteris, DB 35 Metabase).
RCH-AAAAMMJJ-NNNN — [Objet de la recherche]
| Date | AAAA-MM-JJ |
|---|---|
| Service | [nom du service] |
| Contexte | [Pourquoi cette recherche — quelle question, quel besoin, quel problème] |
| Outils utilisés | [MCP utilisé / API directe / PowerShell / Python / recherche web...] |
| Requête | [query exacte, paramètres, filtres, commandes] |
Résultats
[Description des résultats obtenus — texte libre, liste, tableau selon le volume]
Points clés
- [Insight 1 — ce qui est important ou surprenant]
- [Insight 2]
- [Insight 3]
Limites
[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties]
Localisation des ressources
| URLs | [liens directs vers les ressources trouvées] |
|---|---|
| Chemins | [chemins fichiers, répertoires, arborescences] |
| IDs | [IDs containers, pages, assets, items...] |
| Auteurs / Source | [auteurs, éditeurs, provenance] |
| Métadonnées | [dates, formats, tailles, langues, coordonnées...] |
Tags
#tag1 #tag2 #tag3
Suite / Pistes
[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer]
21_Prometheus_les explorations
Journal des recherches réalisées avec Claude Code sur le service Prometheus.
Documentation technique : https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/172
Chaque entrée est automatiquement enregistrée dans la table recherches (PostgreSQL Alteris, DB 35 Metabase).
RCH-AAAAMMJJ-NNNN — [Objet de la recherche]
| Date | AAAA-MM-JJ |
|---|---|
| Service | [nom du service] |
| Contexte | [Pourquoi cette recherche — quelle question, quel besoin, quel problème] |
| Outils utilisés | [MCP utilisé / API directe / PowerShell / Python / recherche web...] |
| Requête | [query exacte, paramètres, filtres, commandes] |
Résultats
[Description des résultats obtenus — texte libre, liste, tableau selon le volume]
Points clés
- [Insight 1 — ce qui est important ou surprenant]
- [Insight 2]
- [Insight 3]
Limites
[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties]
Localisation des ressources
| URLs | [liens directs vers les ressources trouvées] |
|---|---|
| Chemins | [chemins fichiers, répertoires, arborescences] |
| IDs | [IDs containers, pages, assets, items...] |
| Auteurs / Source | [auteurs, éditeurs, provenance] |
| Métadonnées | [dates, formats, tailles, langues, coordonnées...] |
Tags
#tag1 #tag2 #tag3
Suite / Pistes
[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer]
22_Readeck_les explorations
Journal des recherches réalisées avec Claude Code sur le service Readeck.
Documentation technique : https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/173
Chaque entrée est automatiquement enregistrée dans la table recherches (PostgreSQL Alteris, DB 35 Metabase).
RCH-AAAAMMJJ-NNNN — [Objet de la recherche]
| Date | AAAA-MM-JJ |
|---|---|
| Service | [nom du service] |
| Contexte | [Pourquoi cette recherche — quelle question, quel besoin, quel problème] |
| Outils utilisés | [MCP utilisé / API directe / PowerShell / Python / recherche web...] |
| Requête | [query exacte, paramètres, filtres, commandes] |
Résultats
[Description des résultats obtenus — texte libre, liste, tableau selon le volume]
Points clés
- [Insight 1 — ce qui est important ou surprenant]
- [Insight 2]
- [Insight 3]
Limites
[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties]
Localisation des ressources
| URLs | [liens directs vers les ressources trouvées] |
|---|---|
| Chemins | [chemins fichiers, répertoires, arborescences] |
| IDs | [IDs containers, pages, assets, items...] |
| Auteurs / Source | [auteurs, éditeurs, provenance] |
| Métadonnées | [dates, formats, tailles, langues, coordonnées...] |
Tags
#tag1 #tag2 #tag3
Suite / Pistes
[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer]
23_Syncthing_les explorations
Journal des recherches réalisées avec Claude Code sur le service Syncthing.
Documentation technique : https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/174
Chaque entrée est automatiquement enregistrée dans la table recherches (PostgreSQL Alteris, DB 35 Metabase).
RCH-AAAAMMJJ-NNNN — [Objet de la recherche]
| Date | AAAA-MM-JJ |
|---|---|
| Service | [nom du service] |
| Contexte | [Pourquoi cette recherche — quelle question, quel besoin, quel problème] |
| Outils utilisés | [MCP utilisé / API directe / PowerShell / Python / recherche web...] |
| Requête | [query exacte, paramètres, filtres, commandes] |
Résultats
[Description des résultats obtenus — texte libre, liste, tableau selon le volume]
Points clés
- [Insight 1 — ce qui est important ou surprenant]
- [Insight 2]
- [Insight 3]
Limites
[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties]
Localisation des ressources
| URLs | [liens directs vers les ressources trouvées] |
|---|---|
| Chemins | [chemins fichiers, répertoires, arborescences] |
| IDs | [IDs containers, pages, assets, items...] |
| Auteurs / Source | [auteurs, éditeurs, provenance] |
| Métadonnées | [dates, formats, tailles, langues, coordonnées...] |
Tags
#tag1 #tag2 #tag3
Suite / Pistes
[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer]
24_Yourls_les explorations
Journal des recherches réalisées avec Claude Code sur le service Yourls.
Documentation technique : https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/175
Chaque entrée est automatiquement enregistrée dans la table recherches (PostgreSQL Alteris, DB 35 Metabase).
RCH-AAAAMMJJ-NNNN — [Objet de la recherche]
| Date | AAAA-MM-JJ |
|---|---|
| Service | [nom du service] |
| Contexte | [Pourquoi cette recherche — quelle question, quel besoin, quel problème] |
| Outils utilisés | [MCP utilisé / API directe / PowerShell / Python / recherche web...] |
| Requête | [query exacte, paramètres, filtres, commandes] |
Résultats
[Description des résultats obtenus — texte libre, liste, tableau selon le volume]
Points clés
- [Insight 1 — ce qui est important ou surprenant]
- [Insight 2]
- [Insight 3]
Limites
[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties]
Localisation des ressources
| URLs | [liens directs vers les ressources trouvées] |
|---|---|
| Chemins | [chemins fichiers, répertoires, arborescences] |
| IDs | [IDs containers, pages, assets, items...] |
| Auteurs / Source | [auteurs, éditeurs, provenance] |
| Métadonnées | [dates, formats, tailles, langues, coordonnées...] |
Tags
#tag1 #tag2 #tag3
Suite / Pistes
[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer]
25_StirlingPDF
RCH-20260802-0001 — Echec OCR sur images PNG — deux refus cumules d'ocrmypdf (canal alpha + DPI absent)
| Date | 2026-08-02 |
|---|---|
| Service | StirlingPDF |
| Contexte | Julien signale une erreur HTTP 500 lors d'un OCR sur une image PNG via StirlingPDF. L'interface web n'affiche aucun detail exploitable, le diagnostic passe par les logs du container. |
| Outils utilisés | docker logs stirling-pdf, API /api/v1/misc/ocr-pdf, Pillow, tesseract --list-langs |
| Requête | POST /api/v1/misc/ocr-pdf (multipart fileInput, languages=[fra], ocrType=Force-OCR) sur PNG RGBA, puis sur variantes aplaties et converties, avec mesure docker stats en parallele. |
Résultats
Deux erreurs distinctes et cumulees dans ocrmypdf 17.4.0, revelees seulement dans les logs : (1) UnsupportedImageFormatError — The input image has an alpha channel ; (2) une fois l'alpha retire, DpiError — Input file is an image, but has no resolution (DPI) in its metadata. StirlingPDF ne transmet pas l'option --image-dpi a ocrmypdf, donc tout PNG sans DPI dans ses metadonnees echoue. Deux contournements valides en test : voie interface web (Convert > Image to PDF puis OCR sur le PDF, HTTP 200) et voie scriptee (aplatissement de l'alpha sur fond blanc + DPI force a 300, HTTP 200). Texte reconnu restitue a l'identique sur une page de test en francais. Mesure memoire : pic a 894 Mio pour une seule page A4 300 dpi.
Points clés
- L'interface web ne remonte pas la cause : le diagnostic exige docker logs stirling-pdf
- Les deux erreurs sont sequentielles — corriger l'alpha seul ne suffit pas, le DPI bloque ensuite
- Convertir l'image en PDF avant l'OCR neutralise les deux problemes sans outil local
- 6 langues tesseract installees : fra, eng, deu, por, chi_sim, osd
- ocrmypdf et tesseract sont des process Python hors JVM : -Xmx ne les borne pas, seul le plafond cgroup du container s'applique
- La limite de 1 Go prevue pour l'allegement du 2026-08-02 aurait provoque un OOM kill pendant l'OCR — portee a 2 Go
Limites
Mesure realisee sur une page A4 300 dpi generee synthetiquement ; un document multi-pages ou un scan haute resolution consommera davantage. Le pic de 894 Mio est un plancher, pas un maximum.
Localisation des ressources
| URLs | ["https://spdf.juxjux.ovh", "https://spdf.juxjux.ovh/swagger-ui/index.html"] |
|---|---|
| Chemins | ["D:\\Syncthing\\Jux_univers\\Jux-scripts\\Stirling-OCR\\ocr_image.py", "D:\\Syncthing\\Jux_univers\\Jux-scripts\\Stirling-OCR\\README.md", "/home/debian/stirling-compose-new.yml", "/home/debian/stirling-compose-new.yml.orig1g"] |
| IDs | ["stack Portainer 89", "container stirling-pdf", "page BookStack 211"] |
| Auteurs / Source | — |
| Métadonnées | {"ocrmypdf": "17.4.0", "tesseract": "5.3.4", "endpoint_ocr": "POST /api/v1/misc/ocr-pdf", "pic_memoire_ocr": "894 MiB / page A4 300 dpi", "limite_memoire_retenue": "2g"} |
Tags
#StirlingPDF #OCR #ocrmypdf #tesseract #PNG #alpha #DPI #memoire #Docker
Suite / Pistes
Verifier apres l'application du compose allege (2026-08-02 19h) que compress-pdf ET l'OCR fonctionnent toujours avec memory=2g et -Xmx512m.
RCH-20260530-0001 — Mise en place API StirlingPDF pour compression PDF automatisée (workflow geo_loud)
| Date | 2026-05-30 |
|---|---|
| Service | StirlingPDF |
| Contexte | Étape 3 du workflow geo_loud : automatiser la compression des 127 PDFs lourds (>75 Mo) déplacés dans \\NASMAISON\foxy\geo_loud\. Objectif : appeler l'API StirlingPDF depuis le PC, écraser chaque fichier avec sa version compressée, mettre à jour la DB SQLite. Fichier de test : 000209_L'inde.pdf (314 Mo). |
| Outils utilisés | StirlingPDF API REST (JWT Bearer) | curl.exe | plink (PuTTY) pour SSH nginx | Python 3.14 + requests | SQLite nas_geographie.db |
| Requête API | POST https://spdf.juxjux.ovh/api/v1/misc/compress-pdf — multipart/form-data champ fileInput, header Authorization: Bearer <token> |
Résultats
Auth JWT résolue. nginx corrigé (client_max_body_size 500M). Test de compression réussi sur 000209_L'inde.pdf : 314 Mo → 311.7 Mo (0.7% de gain — PDF déjà optimisé en images JPEG). Script nas_geo_compress.py opérationnel pour traitement en batch de tous les fichiers.
Points clés
- Auth imposée : malgré
DOCKER_ENABLE_SECURITY=falsedans la stack Docker, StirlingPDF impose un compte admin au premier lancement. Compte créé : admin / Motdepasse18! - Endpoint de login :
POST /api/v1/auth/loginavec body JSON{"username":"admin","password":"Motdepasse18!"}→ réponse : JWT dans.session.access_token, valable 24h - Utilisation du token : header
Authorization: Bearer <token>sur chaque appel API - nginx : client_max_body_size par défaut = 1 Mo → erreur 413 sur gros fichiers. Correction : ajout de
client_max_body_size 500M;dans/etc/nginx/sites-enabled/spdf.juxjux.ovh(via plink/SSH), puissudo nginx -s reload - Endpoint compression :
POST /api/v1/misc/compress-pdf— multipart avec champfileInput— retourne le PDF compressé directement dans le corps de la réponse (binary) - Gain variable : PDFs avec images JPEG déjà compressées → gain faible (<1%). PDFs texte/vectoriel ou images PNG → gain potentiellement important (30–70%)
- PowerShell inadapté aux gros fichiers : concaténation de byte arrays → OutOfMemoryException sur 314 Mo. Utiliser curl.exe ou Python requests
- Spec API :
/v3/api-docsretourne le HTML de la SPA React. Documentation disponible dans la Swagger UI interactive :https://spdf.juxjux.ovh/swagger-ui/index.html(après login)
Limites
- Token JWT expire après 24h — pour des batchs très longs, prévoir un re-login automatique
- La compression StirlingPDF n'expose pas de paramètre de niveau dans cette version — niveau par défaut uniquement
- Le fichier transite en RAM sur le VPS pendant le traitement — fichiers >500 Mo potentiellement problématiques selon la RAM disponible
Script nas_geo_compress.py
Emplacement : C:\Users\eliob\.claude\nas_geo_compress.py
Lancement : py C:\Users\eliob\.claude\nas_geo_compress.py
Dépendances : pip install requests (sqlite3 et os natifs Python)
Le script ajoute automatiquement les colonnes taille_compresse_octets et date_compression à la table fichiers si elles n'existent pas encore.
"""
Étape 3 du workflow geo_loud : compression PDF via StirlingPDF.
- Lit les fichiers statut='deplace' dans nas_geographie.db
- Envoie chaque PDF à l'API StirlingPDF
- Écrase le fichier d'origine avec la version compressée
- Met à jour la DB (taille_compresse_octets, date_compression)
"""
import sqlite3
import requests
import os
from datetime import datetime
DB_PATH = r"C:\Users\eliob\Documents\nas_geographie.db"
GEO_LOUD = r"\\NASMAISON\foxy\geo_loud"
STIRLING_URL = "https://spdf.juxjux.ovh"
STIRLING_USER = "admin"
STIRLING_PASS = "Motdepasse18!"
def get_token():
r = requests.post(
f"{STIRLING_URL}/api/v1/auth/login",
json={"username": STIRLING_USER, "password": STIRLING_PASS},
timeout=30,
)
r.raise_for_status()
return r.json()["session"]["access_token"]
def init_db_columns(conn):
cur = conn.cursor()
cols = {row[1] for row in cur.execute("PRAGMA table_info(fichiers)")}
if "taille_compresse_octets" not in cols:
cur.execute("ALTER TABLE fichiers ADD COLUMN taille_compresse_octets INTEGER")
if "date_compression" not in cols:
cur.execute("ALTER TABLE fichiers ADD COLUMN date_compression TEXT")
conn.commit()
def get_pending(conn):
cur = conn.cursor()
cur.execute("""
SELECT id, nom, chemin_geo_loud, taille_octets
FROM fichiers
WHERE statut = 'deplace'
AND extension IN ('.pdf', '.PDF')
AND (date_compression IS NULL)
ORDER BY taille_octets DESC
""")
return cur.fetchall()
def compress_file(token, filepath):
with open(filepath, "rb") as f:
r = requests.post(
f"{STIRLING_URL}/api/v1/misc/compress-pdf",
headers={"Authorization": f"Bearer {token}"},
files={"fileInput": (os.path.basename(filepath), f, "application/pdf")},
timeout=600,
stream=True,
)
r.raise_for_status()
return r.content
def update_db(conn, file_id, taille_compresse):
conn.execute("""
UPDATE fichiers
SET taille_compresse_octets = ?, date_compression = ?
WHERE id = ?
""", (taille_compresse, datetime.now().isoformat(), file_id))
conn.commit()
def fmt_mo(octets):
return f"{octets / 1_048_576:.1f} Mo"
def main():
print("Connexion à StirlingPDF...")
token = get_token()
print("Token JWT OK")
conn = sqlite3.connect(DB_PATH)
init_db_columns(conn)
pending = get_pending(conn)
print(f"{len(pending)} fichier(s) PDF à compresser\n")
if not pending:
print("Rien à faire.")
conn.close()
return
total_avant = sum(r[3] for r in pending)
total_apres = 0
ok = 0
errors = []
for i, (file_id, nom, chemin_geo_loud, taille_avant) in enumerate(pending, 1):
filepath = chemin_geo_loud or os.path.join(GEO_LOUD, nom)
if not os.path.exists(filepath):
print(f"[{i}/{len(pending)}] ABSENT {nom}")
errors.append((nom, "fichier absent"))
continue
taille_reel_avant = os.path.getsize(filepath)
print(f"[{i}/{len(pending)}] {nom}")
print(f" avant : {fmt_mo(taille_reel_avant)}", end=" ", flush=True)
try:
compressed = compress_file(token, filepath)
taille_apres_compression = len(compressed)
gain = (taille_reel_avant - taille_apres_compression) / taille_reel_avant * 100
tmp = filepath + ".tmp"
with open(tmp, "wb") as f:
f.write(compressed)
os.replace(tmp, filepath)
update_db(conn, file_id, taille_apres_compression)
total_apres += taille_apres_compression
ok += 1
print(f"-> après : {fmt_mo(taille_apres_compression)} (gain {gain:.1f}%)")
except Exception as e:
print(f"-> ERREUR : {e}")
errors.append((nom, str(e)))
tmp = filepath + ".tmp"
if os.path.exists(tmp):
os.remove(tmp)
conn.close()
print(f"\n{'='*50}")
print(f"Terminé : {ok}/{len(pending)} compressés")
if ok:
gain_total = (total_avant - total_apres) / total_avant * 100
print(f"Volume avant : {fmt_mo(total_avant)}")
print(f"Volume après : {fmt_mo(total_apres)}")
print(f"Gain total : {gain_total:.1f}% ({fmt_mo(total_avant - total_apres)} récupérés)")
if errors:
print(f"\nErreurs ({len(errors)}) :")
for nom, msg in errors:
print(f" {nom} : {msg}")
if __name__ == "__main__":
main()
Localisation des ressources
| URLs | https://spdf.juxjux.ovh (UI) | https://spdf.juxjux.ovh/swagger-ui/index.html (API docs, après login) |
|---|---|
| Chemins | Script : C:\Users\eliob\.claude\nas_geo_compress.py | DB : C:\Users\eliob\Documents\nas_geographie.db | Fichiers source : \\NASMAISON\foxy\geo_loud\ | nginx vhost : /etc/nginx/sites-enabled/spdf.juxjux.ovh |
| IDs | Stack Portainer : stirlingpdf (ID 89) | Container : stirling-pdf | Port interne : 8090 |
| Métadonnées | {"fichiers_a_traiter": 127, "volume_total_go": 13.577, "test_fichier": "000209_L-inde.pdf", "test_avant_mo": 314, "test_apres_mo": 311.7, "test_gain_pct": 0.7, "nginx_max_body": "500M", "token_duree_h": 24} |
Tags
#StirlingPDF #compression #PDF #geo_loud #API #JWT #nginx #Python #NAS #workflow
Suite / Pistes
1/ Lancer le script sur l'ensemble des 127 fichiers — surveiller le gain réel par catégorie de PDF.
2/ Mettre à jour la page BookStack 210 avec les colonnes DB ajoutées (taille_compresse_octets, date_compression) et le bilan de compression une fois le batch terminé.
3/ Si le gain moyen est insuffisant, explorer d'autres niveaux de compression StirlingPDF ou un outil alternatif (Ghostscript direct).
4/ Après compression de tous les fichiers : lancer l'étape 4 (restauration) via nas_geo_loud.py restaurer.
02_Claude et le NAS
260801 - Mon Linux OS sur SASNEXTE
Claude prend la main en MCP pour monter et manager une distribution Linux ubiquiste - disponible
260528_Essai sur \\NASMAISON\foxy\Géographie\
Workflow geo_loud — Optimisation des fichiers lourds
Contexte
Le dossier \\NASMAISON\foxy\Géographie\ contient 1 312 fichiers (PDF et EPUB) pour un total de 32,9 Go. Parmi eux, 127 fichiers dépassent 75 Mo et représentent 13,6 Go — soit 41 % du volume total concentré sur moins de 10 % des fichiers.
L'objectif est de sortir ces fichiers lourds pour les optimiser (compression PDF), puis de les remettre exactement à leur emplacement d'origine sans perdre l'arborescence.
Architecture du système
Fichier Rôle
nas_indexer.py Scanne le NAS et crée la base SQLite
nas_geographie.db Référentiel de tous les fichiers avec métadonnées et statut
nas_geo_loud.py Script checkout/checkin — déplace et restaure les fichiers lourds
La base SQLite est la source de vérité : elle connaît à tout moment l'emplacement original de chaque fichier et son statut.
Colonnes de traçabilité (table fichiers)
Colonne Description
chemin_absolu Chemin d'origine complet sur le NAS
chemin_geo_loud Chemin dans le dossier de travail après déplacement
statut original / deplace / restaure
date_deplacement Horodatage du déplacement
date_restauration Horodatage de la restauration
Workflow complet
Étape 1 — Indexation initiale
1
python nas_indexer.py "\\NASMAISON\foxy\Géographie" --output nas_geographie.db
Résultat : 1 312 fichiers indexés en ~22 secondes, 0 erreur.
Étape 2 — Export (checkout)
Déplace les 127 fichiers > 75 Mo vers \\NASMAISON\foxy\geo_loud\ :
1
2
3
4
python nas_geo_loud.py export \
--db nas_geographie.db \
--dest \\NASMAISON\foxy\geo_loud \
--confirmer
Ce que fait le script :
Interroge la base pour tous les fichiers statut = 'original' et taille > 75 Mo
Renomme chaque fichier {id:06d}_{nom_original} pour éviter les collisions de noms
Déplace physiquement le fichier vers geo_loud/
Met à jour la base : statut = 'deplace', chemin_geo_loud, date_deplacement
Le préfixe numérique garantit l'unicité même si deux sous-dossiers contiennent un fichier de même nom.
Étape 3 — Optimisation PDF
Traiter les fichiers dans \\NASMAISON\foxy\geo_loud\ avec l'outil d'optimisation. Les fichiers peuvent être traités dans n'importe quel ordre et en plusieurs sessions.
Étape 4 — Restauration (checkin)
1
2
3
python nas_geo_loud.py restaurer \
--db nas_geographie.db \
--dest \\NASMAISON\foxy\geo_loud
Ce que fait le script :
Lit tous les enregistrements statut = 'deplace' dans la base
Pour chaque fichier présent dans geo_loud/ : déplace vers son chemin_absolu d'origine
Recrée les sous-dossiers si nécessaire
Met à jour : statut = 'restaure', date_restauration
Ignore les fichiers absents de geo_loud/ (pas encore optimisés)
Étape 5 — Vérification du statut
1
python nas_geo_loud.py statut --db nas_geographie.db
Affiche :
1
2
3
4
Statut Fichiers Total Go
--------------------------------------
deplace 127 13.577
original 1 185 19.275
Vues SQL utiles (Metabase / DB Browser)
1
2
3
4
5
6
7
8
-- Fichiers encore dans geo_loud
SELECT nom, ROUND(taille_octets/1048576.0,1) AS mo, date_deplacement, chemin_absolu
FROM fichiers WHERE statut = 'deplace'
ORDER BY taille_octets DESC;
-- Bilan par statut
SELECT statut, COUNT(*) AS nb, ROUND(SUM(taille_octets)/1073741824.0,3) AS go
FROM fichiers GROUP BY statut;
Paramètres disponibles
Paramètre Défaut Description
--db nas_geographie.db Chemin vers la base SQLite
--dest \\NASMAISON\foxy\geo_loud Dossier de travail
--seuil 75 Seuil en Mo pour la sélection
--confirmer (off) Bypass la confirmation interactive
Ré-indexation après optimisation
1
python nas_indexer.py "\\NASMAISON\foxy\Géographie" --output nas_geographie.db --vider
Fichiers du projet
Fichier Emplacement
nas_indexer.py C:\Users\eliob\Documents\nas_indexer.py
nas_geo_loud.py C:\Users\eliob\Documents\nas_geo_loud.py
nas_rapport.py C:\Users\eliob\Documents\nas_rapport.py
nas_geographie.db C:\Users\eliob\Documents\nas_geographie.db
260611_procédure Komga-PDF par Claude sur StirlingPDF
Présentation
La procédure Komga-PDF est un script de compression de fichiers PDF pour réduire considérablement la taille du stockage des bibliothèques d'ouvrages de la collection de Julien.
L'acquisition de fichiers issus de bases de données Internet accumule des fichiers PDF en haute résolution (images surtout). Ces fichiers sont synchronisés entre les NAS Synology et un disque dur kDrive Infomaniak de 6 To.
Contexte
Des points de montage Rclone relient les répertoires kDrive et les containers Docker installés sur le VPS OVH juxjux.ovh. Ces containers lisent les PDF à la volée — permettant ainsi de construire une infrastructure de très forte densité de connaissances digitales (epub, pdf, images, vidéos, musiques...) avec une solution serveur d'entrée de gamme (10 €/mois tout inclus).
La lecture réseau est multi-support : PC, tablette, téléphone. Elle est aussi nomade, séquentielle et pressée. La compacité des fichiers PDF devient donc nécessaire pour diffuser rapidement sur les réseaux. Un magazine ou un ouvrage informatique ne doit pas peser 130 Mo sur un écran de 10 pouces.
Procédure
- Les nouveaux PDF sont déposés dans le dossier Syncthing :
Syncthing/komga-pdf/depuis n'importe quelle machine (PC Elio+Jux, PC Nexte, Ubuntu, Xiaomi...) - Syncthing synchronise automatiquement vers le VPS :
/home/debian/Documents/komga-pdf/ - Le service
komga-watch(systemd VPS) détecte l'arrivée via inotifywait local - Dès détection,
komga_compress_vps.pycompresse le PDF via StirlingPDF et dépose le résultat dans/home/debian/Documents/komga-compressed/ - Julien range manuellement les PDF compressés vers sasnexte puis dans le dossier thématique de son choix
- Les originaux ne sont jamais supprimés du VPS — Julien valide et conserve si besoin (haute résolution souhaitée)
Architecture technique
| Élément | Chemin / URL |
|---|---|
| Dépôt (toutes machines) | Syncthing/komga-pdf/ |
| Dossier VPS (Syncthing) | /home/debian/Documents/komga-pdf/ |
| Destination VPS | /home/debian/Documents/komga-compressed/ |
| API compression | https://spdf.juxjux.ovh/api/v1/misc/compress-pdf |
| Scripts VPS | /home/debian/komga_compress_vps.py + /home/debian/komga_watch_vps.sh |
| Logs | journalctl -u komga-watch -f (sur le VPS) |
Scripts
Le service tourne entièrement sur le VPS — plus de dépendance Ubuntu ni de SSH persistant.
| Fichier | Rôle |
|---|---|
komga_compress_vps.py |
Compression : liste les PDFs locaux, envoie à StirlingPDF, écrit dans komga-compressed/. Idempotent (ignore les fichiers déjà compressés). |
komga_watch_vps.sh |
Surveillance : traite le backlog au démarrage, puis boucle inotifywait locale. |
/etc/systemd/system/komga-watch.service |
Service system (pas user), actif au boot, Restart=always. |
Gérer le service (VPS)
sudo systemctl status komga-watch
sudo systemctl restart komga-watch
journalctl -u komga-watch -f
Retour d'expérience (2026-06-13) — Refactorisation VPS
Problème de l'architecture Ubuntu : le service tournait sur Ubuntu avec un SSH persistant vers le VPS. Deux défauts structurels :
inotifywaitne détecte pas les fichiers déjà présents au redémarrage du service (backlog silencieux)- Impossible à contrôler depuis Windows/Claude Code
Solution : service systemd sur le VPS lui-même. inotifywait local, pas de SSH persistant. Le script traite le backlog à chaque démarrage avant d'entrer dans la boucle de surveillance.
Résultats de compression (2026-06-13) :
| Fichier | Original | Compressé | Gain |
|---|---|---|---|
| Beaux Arts - Juin 2026.pdf | 75.8 Mo | 61.1 Mo | -19% |
| Connaissance des Arts - Juin 2026.pdf | 57.3 Mo | 35.2 Mo | -39% |
| La Revue du Vin de France - Juin 2026.pdf | 93.3 Mo | 39.9 Mo | -57% |
| Livre lacto fermentation.pdf | 96.6 Mo | 19.6 Mo | -80% |
| Monde Gourmand N°93 - Juin 2026.pdf | 41.2 Mo | 17.4 Mo | -58% |
Points techniques :
- Dossier VPS avec D majuscule :
/home/debian/Documents/(Syncthing sensible à la casse) - Race condition inotifywait/Syncthing : attente 3s après événement, script idempotent
- Python :
/usr/bin/python3(système,requests2.28.1 disponible) - StirlingPDF auth : JWT via
POST /api/v1/auth/login→session.access_token, valable 24h - Fichiers
sync-conflictSyncthing filtrés automatiquement par le script
Retour d'expérience (2026-06-12)
Résultats de compression :
| Fichier | Original | Compressé | Gain |
|---|---|---|---|
| Monde Gourmand N°93 - Juin 2026.pdf | 42 Mo | 17 Mo | -58% |
| Connaissance des Arts - Juin 2026.pdf | 57 Mo | 35 Mo | -39% |
260614 - procedure Joplin-compression
Contexte — instructions de Julien (260614)
J'utilise l'application Joplin sur tous mes appareils. C'est ma mémoire de tout (travail, hobbies, maison...) et donc à force, la base de données se remplit. Elle se compose de notes à l'intérieur desquelles on trouve des images. Même en n'important que des captures d'écran, le poids de ces images est devenu important — de l'ordre de 300 Mo initialement estimé (476 Mo constatés en réalité, voir ci-dessous).
Appareils synchronisés sous Joplin :
- VPS Juxjux.OVH (serveur de sync)
- PC Nexte (PC du travail de Julien)
- PC Elio+Jux (PC maison de Julien)
- Mobile Xiaomi T15pro de Julien
- Tablette Samsung S5 de Julien
- Session Ubuntu sur clé SSD de Julien
Objectif de la procédure :
- Compresser le stock d'images contenues dans la base de données Joplin via un process fiable de remplacement
- Monter un système de compression automatique quotidienne des nouvelles images
Principes définis par Julien :
- Tenir un carnet de bord (observatoire) du poids digital de la BDD Joplin dans la page BookStack Joplin, avec les 15 pièces jointes les plus lourdes
- Mettre en place sur le VPS une procédure duplication → compression → remplacement d'images, qui se propage via la sync Joplin sur tous les appareils
Exploration technique — Claude, 14/06/2026
Infrastructure Joplin sur le VPS
Contrairement à ce qu'on pourrait attendre, Joplin Server n'utilise pas SQLite mais PostgreSQL.
| Container | Image | Rôle |
|---|---|---|
joplin |
joplin/server:latest |
Serveur de sync Joplin |
joplin-db |
postgres:15-alpine |
Base de données |
joplin-nginx |
nginx:alpine |
Reverse proxy interne |
joplin_to_obsidian |
image custom | Container migration (actif, sans impact) |
Volume de données : /home/debian/joplin-data → /home/joplin/.config/joplin (bind mount)
Connexion DB : POSTGRES_HOST=joplin-db, POSTGRES_DATABASE=joplin, POSTGRES_USER=joplin
Important : le port 5432 de joplin-db n'est pas exposé à l'extérieur du réseau Docker. Tout script de manipulation doit tourner sur le VPS et se connecter via l'IP interne Docker.
Structure de la base de données
La table centrale est items (23 tables au total). Chaque note, ressource et paramètre Joplin est une ligne dans cette table.
Colonnes clés :
content(bytea) — données binaires brutescontent_size(integer) — taille en octetscontent_storage_id= 1 → stockage de typeDatabase(tout est dans PostgreSQL, pas de fichiers externes)jop_type— type d'item Joplinupdated_time— timestamp de dernière modification (utilisé par les clients pour détecter les changements à sync)
Répartition par type :
| jop_type | Signification | Nombre | Poids total |
|---|---|---|---|
| 0 | Ressource (image/fichier joint) | 736 | 476 MB |
| 1 | Note | 699 | 8,7 MB |
| 4 | Tag | 733 | 4,5 MB |
| 13 | NoteTag (relation note↔tag) | 250 | 3,9 MB |
| 2 | Carnet (Folder) | 94 | 707 KB |
| 6 | Master Key | 87 | 19 KB |
| 5 | Setting | 39 | — |
Analyse des ressources (jop_type = 0)
Les ressources sont stockées comme bytes bruts dans la colonne content. Le format est détectable via les magic bytes :
- PNG (
\x89PNG) — majorité des ressources - JPEG (
\xff\xd8) — portion significative - ZIP (
PK\x03\x04) — cas particulier : ZIP contenant plusieurs imagespage_1.png,page_2.png... (documents multi-pages)
La colonne mime_type est vide pour toutes les ressources — le type est implicite dans les bytes du contenu.
Top 15 ressources les plus lourdes (état initial) :
| Rang | ID | Taille | Format |
|---|---|---|---|
| 1 | 0xh87pWrRt82z0DbO9n3yQ | 12,2 MB | ZIP (page_1.png 7MB + page_2.png 5MB) |
| 2 | M0C32hKC2hMqPAxpRGiVgp | 7,2 MB | PNG |
| 3 | UbAqQY3cEbH62vioIHU6Pj | 6,0 MB | PNG |
| 4 | ZPQJVSjptMSxE71pV7JbAt | 5,9 MB | PNG |
| 5 | h4Lhw1Trx9wgmD7doX9NyZ | 5,9 MB | PNG |
| 6 | sbktcNb4IUj0yIovgDt0fL | 5,3 MB | PNG |
| 7 | jtzuGpvrRTR12iLzwhcSNn | 5,2 MB | PNG |
| 8 | VasIoF2e9EGuNQt38aOFMx | 4,9 MB | JPEG |
| 9 | ZACDcQWzQzDLdnV7Qnf933 | 4,3 MB | PNG |
| 10 | hExoJEEWT2tHz1demE5Nhm | 4,3 MB | PNG |
| 11 | veu4HT3bStx07gRUlAEYvG | 4,2 MB | PNG |
| 12 | bz9Twmb2F5lj0mPIQi48IB | 4,2 MB | JPEG |
| 13 | TzWK21r4n0yvbEtJh02DGB | 4,2 MB | JPEG |
| 14 | eD165w1bdEHJg0tq3qWok5 | 4,2 MB | PNG |
| 15 | HD4SeqIx252nP9nh8HDVnH | 4,1 MB | PNG |
Architecture retenue
Choix de compression — décision Julien, 14/06/2026
PNG → JPEG 85% (lossy). Toutes les images, qu'elles soient PNG ou JPEG à l'origine, sont converties/re-sauvegardées en JPEG qualité 85. Gain estimé : 50–75% par image. Acceptable pour des captures d'écran.
Pour les ZIP multi-pages : chaque image interne est convertie en JPEG 85%, le ZIP est reconstruit.
Phase 1 — Observatoire
Script joplin_observatoire.py sur le VPS :
- Connexion psycopg2 à joplin-db via IP réseau Docker interne
- Calcul des stats globales (taille totale, nombre d'items par format)
- Liste des 15 ressources les plus lourdes avec format et taille
- Mise à jour de la page BookStack Joplin (page 166) avec ces informations
Phase 2 — Compression (script principal)
Script joplin_compress.py sur le VPS :
Connexion : psycopg2 → IP Docker interne de joplin-db : 5432
Traitement par ressource :
- Lire le blob
contentdepuisitems(jop_type=0) - Détecter le format (magic bytes)
- Ouvrir avec Pillow, convertir en JPEG 85 (
quality=85, optimize=True) - Pour les ZIP multi-pages : dézipper → compresser chaque image → reconstruire le ZIP
- Si le gain est > 5% : mettre à jour
content,content_size,updated_timeen base - Logger le résultat (ID, taille avant, taille après, ratio)
Tracking des items traités : fichier JSON local /home/debian/joplin_compress_log.json — évite de retraiter les ressources déjà compressées lors des passages quotidiens.
Propagation sync : Joplin détecte les changements via updated_time. Lors de la prochaine synchronisation de chaque client, les ressources compressées sont re-téléchargées automatiquement.
Phase 3 — Service systemd (cron quotidien)
Timer systemd joplin-compress.timer → joplin-compress.service :
- Déclenchement quotidien (3h du matin)
- Traite uniquement les nouvelles ressources (non présentes dans le log JSON)
- Met à jour l'observatoire BookStack après chaque passage
Mise en production — 14/06/2026
Résultat du premier run (stock complet)
| Ressources traitées | 736 au total |
|---|---|
| Compressées | 424 |
| Ignorées (gain < 5%) | 312 |
| Erreurs | 0 |
| Poids avant | 476 Mo |
| Poids après | 119,7 Mo |
| Économie | 356 Mo (-78,9%) |
Scripts déployés sur le VPS
| Script | Rôle | Options |
|---|---|---|
/home/debian/joplin_compress.py |
Compression Pillow PNG/JPEG → JPEG 85%, ZIP multi-pages, mise à jour PostgreSQL | --dry-run (simulation) / --limit N (N ressources max) |
/home/debian/joplin_observatoire.py |
Stats DB + top 15 → mise à jour page BookStack Joplin (ID 166) | — |
Log tracking : /home/debian/joplin_compress_log.json — liste des ressources déjà traitées, évite les doublons aux runs suivants.
Timer systemd
| Service | joplin-compress.service |
|---|---|
| Timer | joplin-compress.timer |
| Déclenchement | Chaque nuit à 3h UTC (OnCalendar=*-*-* 03:00:00) |
| Logs | /var/log/joplin-compress.log |
| Statut | active (waiting) — prochain run : 15/06/2026 03:00 UTC |
Notes techniques
- joplin-db IP Docker interne :
172.27.0.4(peut changer si le container est recréé — vérifier avecdocker inspect joplin-db -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}') - La compression modifie
content,content_sizeetupdated_timedans la tableitems - Les clients Joplin re-téléchargent les ressources modifiées lors de la prochaine synchronisation (détection via
updated_time) - Les images à fond transparent (RGBA/LA/P) sont aplaties sur fond blanc avant conversion JPEG
260615 - Immich performance
260615 -instructions pour la procédure Immich Performance
Les photos de famille (et des vidéos) sont un patrimoine important pour notre famille. Donc elles font l'objet de beaucoup d'attention....et de volume de stockage. Les photos sont stockées sur les 2 NAS - Nasmaison et Sasnexte synchronisées à travers les outils Synology. A partir de Sasnexte, un script journalier Synology les propulse sur le VPS Kdrive pour être lues en lecture seule par toute la famille (elles sont également sur deux autres disques durs USB....).
Aujourd'hui, le dossier photos du Sasnexte que l'on doit considérer comme le cœur de ce dispositif nécessite une observation un peu plus fine car :
- des compressions vidéos doivent être faites pour les rendre plus faciles en lecture sur les portables en mobilité
- des compressions images lorsque le poids est aberrant pour l'usage
- des doublons existent forcément.
Immich performance est une procédure importante du livre de Claude.
Réponse de Claude
Inventaire par Claude Code le 01/10/2025
SAS_NEXTE@NEXTE:~$ sudo du -h --max-depth=2 /volume1/photo/ | sort -h
0 /volume1/photo/1968-1994 - photos famille dont Noumea/1982
0 /volume1/photo/2009-mariage Zymny
0 /volume1/photo/2014- été/140714-Lyon chez Pierre
0 /volume1/photo/2020 - Automne Noel/noel2020
0 /volume1/photo/2024/202401 - Hiver Automne
0 /volume1/photo/2025/DCIM
0 /volume1/photo/@eaDir/clientd.tmp.dir
0 /volume1/photo/@eaDir/cloud.tmp.dir
0 /volume1/photo/@eaDir/@recycle
0 /volume1/photo/@eaDir/@tmp
4.0K /volume1/photo/@eaDir/@drive.queues
24K /volume1/photo/@eaDir/sharesnap_share_configuration
32K /volume1/photo/2010 - été/@eaDir
40K /volume1/photo/2011- Ete/@eaDir
52K /volume1/photo/2021-été covidé/@eaDir
84K /volume1/photo/@eaDir/980710-photo CV julien.jpg
264K /volume1/photo/@eaDir/131124-elio pas content.jpg
352K /volume1/photo/2009 Nouvel an Réveillon/@eaDir
432K /volume1/photo/@eaDir/2015-soirée mexicaine.jpg
440K /volume1/photo/1968-1994 - photos famille dont Noumea/Givet
548K /volume1/photo/@eaDir/150314-Zoee en 18X24.png
616K /volume1/photo/2009 Nouvel an Réveillon
656K /volume1/photo/1968-1994 - photos famille dont Noumea/1977
656K /volume1/photo/@eaDir/7b06435c-6bad-4eb0-aa38-af03bdfbfbc8.jpg
672K /volume1/photo/@eaDir/PhotoLab445379.jpg
792K /volume1/photo/@eaDir/160220-elio en 18X24.png
848K /volume1/photo/2011 - printemps/@eaDir
900K /volume1/photo/2016 ACDC/@eaDir
1.5M /volume1/photo/1968-1994 - photos famille dont Noumea/1976
1.7M /volume1/photo/1968-1994 - photos famille dont Noumea/Pierre-001
2.1M /volume1/photo/1968-1994 - photos famille dont Noumea/1969
3.0M /volume1/photo/1968-1994 - photos famille dont Noumea/1978
3.4M /volume1/photo/1968-1994 - photos famille dont Noumea/1968
3.4M /volume1/photo/1968-1994 - photos famille dont Noumea/1980
3.5M /volume1/photo/2014-mars-repas chez maman/@eaDir
4.1M /volume1/photo/1999/@eaDir
4.3M /volume1/photo/2014 - 4 ans Zoée/@eaDir
4.9M /volume1/photo/1968-1994 - photos famille dont Noumea/1979
4.9M /volume1/photo/2016 ACDC
5.3M /volume1/photo/1986 - Californie/@eaDir
5.3M /volume1/photo/Cartes de voeux/@eaDir
5.5M /volume1/photo/2010-hiver/@eaDir
6.0M /volume1/photo/1968-1994 - photos famille dont Noumea/1992
6.6M /volume1/photo/1930-2016 - Photos BERTRAND MER/Elio
6.6M /volume1/photo/2016-best photos pour 70 ans/Elio
6.7M /volume1/photo/1999
6.9M /volume1/photo/1968-1994 - photos famille dont Noumea/Etats-Unis 1986
7.4M /volume1/photo/2015 - Noël/@eaDir
7.6M /volume1/photo/1930-2016 - Photos BERTRAND MER/Les communions solennelle s
7.6M /volume1/photo/2016-best photos pour 70 ans/Les communions solennelles
7.8M /volume1/photo/1968-1994 - photos famille dont Noumea/1994
7.9M /volume1/photo/2013-Serbie/@eaDir
8.0M /volume1/photo/2014/@eaDir
8.4M /volume1/photo/1968-1994 - photos famille dont Noumea/1990
8.5M /volume1/photo/2004 - été/@eaDir
8.5M /volume1/photo/2022-Noel/@eaDir
8.6M /volume1/photo/2015 - Automne/@eaDir
8.9M /volume1/photo/1930-2016 - Photos BERTRAND MER/Les amis, la famille en n oir et blanc
8.9M /volume1/photo/2016-best photos pour 70 ans/Les amis, la famille en noir et blanc
9.5M /volume1/photo/1968-1994 - photos famille dont Noumea/1981
9.9M /volume1/photo/2018 - Noel/@eaDir
10M /volume1/photo/#recycle/2016 - 70 ans maman_DiskStation_Nov-04-1745-2020 _CaseConflict
11M /volume1/photo/1930-2016 - Photos BERTRAND MER/Album de la famille de Re née Campanella
11M /volume1/photo/2010 - naissance Zoée/@eaDir
11M /volume1/photo/2014/Noël 2014
11M /volume1/photo/2016-best photos pour 70 ans/Album de la famille de Renée Campanella
12M /volume1/photo/2013 Marseille/@eaDir
12M /volume1/photo/2014-mars-repas chez maman
12M /volume1/photo/2015-Hiver/@eaDir
12M /volume1/photo/2015-inventaire maison assurances/@eaDir
13M /volume1/photo/1968-1994 - photos famille dont Noumea/1975
14M /volume1/photo/1968-1994 - photos famille dont Noumea/1983
15M /volume1/photo/2005 - été/@eaDir
16M /volume1/photo/2016-mai juin/@eaDir
16M /volume1/photo/2016 - Valras/@eaDir
17M /volume1/photo/2004 - été
17M /volume1/photo/2010 - naissance Zoée
18M /volume1/photo/1968-1977/@eaDir
18M /volume1/photo/2014 - 4 ans Zoée
18M /volume1/photo/2014/Anniversaire_Elio_2014
18M /volume1/photo/2016-avril avant crète/@eaDir
19M /volume1/photo/1930-2016 - Photos BERTRAND MER/Grand-père Emile et mamie Rosa
19M /volume1/photo/2016-best photos pour 70 ans/Grand-père Emile et mamie Ro sa
21M /volume1/photo/1930-2016 - Photos BERTRAND MER/@eaDir
21M /volume1/photo/1930-2016 - Photos BERTRAND MER/L'album de Papa et Maman
21M /volume1/photo/2016-best photos pour 70 ans/L'album de Papa et Maman
21M /volume1/photo/2016- photos Maman Papa/@eaDir
22M /volume1/photo/2011 - Automne/@eaDir
22M /volume1/photo/2013 Noël/@eaDir
22M /volume1/photo/2014-Hiver Printemps/@eaDir
23M /volume1/photo/2014 - Automne Noel/@eaDir
24M /volume1/photo/2011 - jour de l'an/@eaDir
24M /volume1/photo/2014-mur effondré - Ville de Toulon/@eaDir
25M /volume1/photo/2009 - Papa/@eaDir
25M /volume1/photo/2010-hiver
25M /volume1/photo/2021-été covidé/2021 - après vacances
25M /volume1/photo/Cartes de voeux
26M /volume1/photo/1968-1994 - photos famille dont Noumea/1984
27M /volume1/photo/1930-2016 - Photos BERTRAND MER/Enfants Mer et cousins
27M /volume1/photo/2008 Toscane/@eaDir
27M /volume1/photo/2016 - 70 ans Maman/@eaDir
27M /volume1/photo/2016-best photos pour 70 ans/Enfants Mer et cousins
27M /volume1/photo/2022-automne a Noel/@eaDir
29M /volume1/photo/2018 - Noel
30M /volume1/photo/2008 - mariage Héléna et Jérome/@eaDir
30M /volume1/photo/2012 - Eté/@eaDir
30M /volume1/photo/#recycle/2016 - 70 ans maman_DiskStation_Nov-04-1745-2020 _CaseConflict_1
31M /volume1/photo/2025/2501 à 2502
32M /volume1/photo/2015 - Noël
33M /volume1/photo/2014/Carnaval 2014
34M /volume1/photo/2016-best photos pour 70 ans/@eaDir
35M /volume1/photo/2014-Barcelone/@eaDir
36M /volume1/photo/2013/@eaDir
36M /volume1/photo/2016-Parc Vert Coteau/soirée janvier 2016
36M /volume1/photo/2024/2024 - Nouvel an Arriège
37M /volume1/photo/2015 - Automne
38M /volume1/photo/2014/Février 2014
39M /volume1/photo/2011 - Noel/@eaDir
39M /volume1/photo/2020 - Automne Noel/@eaDir
40M /volume1/photo/2014/Sept_2014_4ans_Zoée
40M /volume1/photo/@eaDir/SYNO@.fileindexdb
41M /volume1/photo/2016-Parc Vert Coteau/avril 2016 état
41M /volume1/photo/2022-Noel
43M /volume1/photo/@eaDir
44M /volume1/photo/2009 - Papa
44M /volume1/photo/2012/@eaDir
45M /volume1/photo/1930-2016 - Photos BERTRAND MER/Papa juin 2009 - Le livre d'Alain
45M /volume1/photo/2016-best photos pour 70 ans/Papa juin 2009 - Le livre d' Alain
47M /volume1/photo/2005 - été
47M /volume1/photo/2008 Toscane
50M /volume1/photo/2019-Cabaret Vert/@eaDir
51M /volume1/photo/2015 - Juillet Valras/@eaDir
52M /volume1/photo/2021-hiver printemps/@eaDir
53M /volume1/photo/2015-Hiver
53M /volume1/photo/2018-défi Genes/@eaDir
54M /volume1/photo/2008 - été Hautes Alpes/@eaDir
54M /volume1/photo/2009 - Elio/@eaDir
55M /volume1/photo/2013-Serbie
58M /volume1/photo/2013 Marseille
58M /volume1/photo/2015-inventaire maison assurances
62M /volume1/photo/2007-1er janvier/@eaDir
62M /volume1/photo/2016 - Valras
64M /volume1/photo/2014- été/@eaDir
67M /volume1/photo/2009 - été Irlande/@eaDir
67M /volume1/photo/2016-mai juin
70M /volume1/photo/1968-1994 - photos famille dont Noumea/Nouméa
70M /volume1/photo/2011- Ete/GARD juillet 2011
71M /volume1/photo/2020 - Hiver Confinement COVID/@eaDir
73M /volume1/photo/2022-hiver à Paques/@eaDir
73M /volume1/photo/2024/202412 - Automne Noel
75M /volume1/photo/2013 - Printemps/@eaDir
76M /volume1/photo/2016-Parc Vert Coteau
76M /volume1/photo/2024/@eaDir
79M /volume1/photo/2012 - Eté/2012 - Bretagne
79M /volume1/photo/2014-Hiver Printemps
81M /volume1/photo/2013 Noël
82M /volume1/photo/2017-Voyage à Turin/@eaDir
84M /volume1/photo/2016-Venasque/@eaDir
86M /volume1/photo/1986 - Californie
88M /volume1/photo/2023-ete/@eaDir
91M /volume1/photo/2009 - été Ardèche/@eaDir
93M /volume1/photo/2016-avril avant crète
94M /volume1/photo/2007-1er janvier
96M /volume1/photo/2021-Automne et Noel/@eaDir
97M /volume1/photo/2008 - été Hautes Alpes
99M /volume1/photo/PhotoLibrary/2025
100M /volume1/photo/2014- Porto - Primavera/@eaDir
107M /volume1/photo/2014-mur effondré - Ville de Toulon
108M /volume1/photo/2023 - Automne Noel/@eaDir
111M /volume1/photo/2009 - été Irlande
111M /volume1/photo/2015- printemps/@eaDir
114M /volume1/photo/2025/2504 et 2505
125M /volume1/photo/2010 - été
125M /volume1/photo/2010 - été/Beauduc
125M /volume1/photo/2014 - Automne Noel
130M /volume1/photo/2016-Crete/@eaDir
131M /volume1/photo/2011 - jour de l'an
138M /volume1/photo/2021-été covidé/2021 avant vacances
139M /volume1/photo/2013
140M /volume1/photo/2018 - Valras/@eaDir
143M /volume1/photo/2016-Automne Noel/@eaDir
145M /volume1/photo/2013-Pays Bas/@eaDir
146M /volume1/photo/2014-Barcelone
150M /volume1/photo/2023-Hiver à Paques/@eaDir
152M /volume1/photo/2008 - mariage Héléna et Jérome
153M /volume1/photo/2017-Automne Noel/@eaDir
154M /volume1/photo/2014/Mai_Juin 2014
157M /volume1/photo/2014/Avril 2014
159M /volume1/photo/2022-automne a Noel
162M /volume1/photo/2009 - été Ardèche
173M /volume1/photo/2014 - 5 jours en Corse/@eaDir
178M /volume1/photo/2016-best photos pour 70 ans/Ma famille pour mes 70 ans
178M /volume1/photo/2020 -Printemps/@eaDir
179M /volume1/photo/1930-2016 - Photos BERTRAND MER
180M /volume1/photo/1968-1994 - photos famille dont Noumea
181M /volume1/photo/2019- Hiver Printemps/@eaDir
181M /volume1/photo/2022 - été Flandres NL Paris/@eaDir
183M /volume1/photo/2012
184M /volume1/photo/2009 - Elio
186M /volume1/photo/2014/2014-été
192M /volume1/photo/2016- photos Maman Papa
203M /volume1/photo/1968-1977
206M /volume1/photo/1967 à 2000 - photos famille Bertrand/@eaDir
213M /volume1/photo/2023-Mai à Vacances Eté/@eaDir
214M /volume1/photo/2019-Automne/@eaDir
222M /volume1/photo/2015 - Juillet Valras
229M /volume1/photo/2020 - Automne Noel
230M /volume1/photo/2018-printemps/@eaDir
258M /volume1/photo/2021-hiver printemps
281M /volume1/photo/2014- été
282M /volume1/photo/2018 - automne noel/@eaDir
323M /volume1/photo/2011 - Noel
325M /volume1/photo/2018-défi Genes
348M /volume1/photo/2005 - naissance Elio/@eaDir
354M /volume1/photo/2011 - printemps
368M /volume1/photo/2011 - Automne
381M /volume1/photo/2017-Hiver-Printemps/@eaDir
384M /volume1/photo/2016-Venasque
407M /volume1/photo/2020 -Printemps
409M /volume1/photo/2016-best photos pour 70 ans
419M /volume1/photo/2016 - 70 ans Maman
434M /volume1/photo/2020 - Hiver Confinement COVID
439M /volume1/photo/2017-Voyage à Turin
460M /volume1/photo/2023-Mai à Vacances Eté
462M /volume1/photo/2011- Ete/LIGURIE aout 2011
500M /volume1/photo/2013 - Printemps
511M /volume1/photo/2023-ete
515M /volume1/photo/2022-hiver à Paques
520M /volume1/photo/2012 - Eté/2012 - été Buis
525M /volume1/photo/2016-Crete
528M /volume1/photo/2014- Porto - Primavera
531M /volume1/photo/2011- Ete
535M /volume1/photo/2023-Vacances D NL B/@eaDir
573M /volume1/photo/2023 - Automne Noel
575M /volume1/photo/2016-été Ré Gers/@eaDir
580M /volume1/photo/2018-Barcelone Primavera Sound/@eaDir
618M /volume1/photo/2019-Cabaret Vert
629M /volume1/photo/2019 Bretagne Alpes/@eaDir
635M /volume1/photo/2013-Pays Bas
663M /volume1/photo/2021-Automne et Noel
667M /volume1/photo/2014
685M /volume1/photo/2015- printemps
700M /volume1/photo/2017-été Scandinavie/@eaDir
718M /volume1/photo/2024/2024 - Eté Italie Autriche
759M /volume1/photo/2018 - Valras
809M /volume1/photo/#recycle/2025
817M /volume1/photo/2016-Automne Noel
846M /volume1/photo/2025/2506 à 2509
860M /volume1/photo/#recycle
907M /volume1/photo/2019-Automne
920M /volume1/photo/2017-Automne Noel
935M /volume1/photo/2023-Hiver à Paques
941M /volume1/photo/2024/2024-Porto
944M /volume1/photo/cecile tri 2022/@eaDir
945M /volume1/photo/PhotoLibrary/DCIM
956M /volume1/photo/2005 - naissance Elio
964M /volume1/photo/2020 - été Vienne Venise/@eaDir
991M /volume1/photo/2025
1.1G /volume1/photo/2014 - 5 jours en Corse
1.1G /volume1/photo/2015-Croatie Autriche/@eaDir
1.1G /volume1/photo/2018-the Alpen/@eaDir
1.1G /volume1/photo/PhotoLibrary
1.2G /volume1/photo/2021-été covidé/2021 - vacances Aout Mont Blanc Cantal
1.2G /volume1/photo/2022 - été Flandres NL Paris
1.3G /volume1/photo/2019- Hiver Printemps
1.3G /volume1/photo/2021-été covidé
1.4G /volume1/photo/2018-printemps
1.5G /volume1/photo/2016-été Ré Gers/Vidéo Aveyron Ré et Gers
1.5G /volume1/photo/2024/2024-Via Reggio
1.8G /volume1/photo/2018 - automne noel
1.9G /volume1/photo/2012 - Eté/2012- été Italia
2.0G /volume1/photo/2017-Hiver-Printemps
2.7G /volume1/photo/2012 - Eté
2.8G /volume1/photo/2019 Bretagne Alpes
2.8G /volume1/photo/2020 - été Vienne Venise
2.9G /volume1/photo/1967 à 2000 - photos famille Bertrand
3.2G /volume1/photo/2023-Vacances D NL B
3.6G /volume1/photo/2018-Barcelone Primavera Sound
3.7G /volume1/photo/cecile tri 2022
3.8G /volume1/photo/2024
4.1G /volume1/photo/2016-été Ré Gers
4.2G /volume1/photo/2017-été Scandinavie
5.7G /volume1/photo/2018-the Alpen
6.4G /volume1/photo/2015-Croatie Autriche
79G /volume1/photo/
Montages Rclone Sasnexte et Kdrive
Montages Rclone Sasnexte et Kdrive
Architecture
NAS Sasnexte (Synology)
└── rclone sync (WebDAV) ──► kDrive Infomaniak
└── rclone mount (FUSE) ──► VPS Jux
└── containers Docker
Le NAS pousse les médias vers kDrive une fois par jour via le planificateur DSM. Le VPS monte kDrive en FUSE en permanence — les containers accèdent aux fichiers en lecture.
Remote rclone (NAS sasnexte)
Fichier : /volume1/homes/SAS_NEXTE/.config/rclone/rclone.conf
[kdrive_music]
type = webdav
url = https://591617.connect.kdrive.infomaniak.com
vendor = other
user = julien.bertrand@nexte.fr
pass = [obfusqué rclone]
Note : le remote s'appelle kdrive_music mais sert à synchroniser tous les contenus (musique, photos, audiobooks, Komga). Nom historique à ne pas confondre avec un remote dédié musique.
Mot de passe WebDAV : régénéré le 2026-06-23 (compte julien.bertrand@nexte.fr, espace kDrive 591617). Mise à jour via rclone config update kdrive_music pass $(rclone obscure NOUVEAU_MDP).
Script unifié (NAS sasnexte)
Emplacement : /volume1/homes/SAS_NEXTE/scripts/sync_kdrive_complete.sh
Planificateur DSM : tâche déclenchée quotidiennement — commande : /volume1/homes/SAS_NEXTE/scripts/sync_kdrive_complete.sh
Note sudo : le script contient sudo -u SAS_NEXTE rclone .... Si la tâche DSM est configurée pour tourner en tant que SAS_NEXTE, retirer le sudo -u SAS_NEXTE (inutile et peut bloquer). Si elle tourne en root, le garder.
#!/bin/bash
RCLONE="/usr/local/bin/rclone"
REMOTE="kdrive_music"
LOG_DIR="/volume1/homes/SAS_NEXTE/logs"
DATE=$(date +%Y%m%d_%H%M%S)
SUMMARY_LOG="$LOG_DIR/sync_${DATE}.log"
mkdir -p "$LOG_DIR"
run_sync() {
local name="$1"
local source="$2"
local dest="${REMOTE}:${3}"
local log="$LOG_DIR/sync_${name}_${DATE}.log"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] === Debut $name ===" >> "$SUMMARY_LOG"
sudo -u SAS_NEXTE "$RCLONE" sync "$source" "$dest" --delete-excluded --ignore-errors --delete-during --fast-list --exclude "@eaDir/**" --exclude "#recycle/**" --exclude "@__thumb/**" --exclude "*.@SynoResource" --exclude "*.@SynoEAStream" --transfers=4 --checkers=8 --timeout=5m --contimeout=2m --log-file="$log" -v
local rc=$?
echo "[$(date '+%Y-%m-%d %H:%M:%S')] === Fin $name (code=$rc) ===" >> "$SUMMARY_LOG"
}
run_sync "audiobooks" "/volume1/audiobooks" "SYNC-pour_VPS/Sync-SASNEXTE/audiobooks"
run_sync "music" "/volume1/music" "SYNC-pour_VPS/Sync-SASNEXTE/music"
run_sync "photo" "/volume1/photo/2026" "SYNC-pour_VPS/Sync-SASNEXTE/photo/2026"
run_sync "komga" "/volume1/Komga" "SYNC-pour_VPS/Sync-SASNEXTE/Komga"
Déploiement : écrire via vi depuis SSH — le heredoc et les éditeurs Windows introduisent des CRLF qui cassent bash. Après édition : sed -i 's/\r//' script.sh pour vérifier.
Syncs actifs
| Nom | Source NAS | Destination kDrive | Notes |
|---|---|---|---|
| audiobooks | /volume1/audiobooks |
SYNC-pour_VPS/Sync-SASNEXTE/audiobooks |
|
| music | /volume1/music |
SYNC-pour_VPS/Sync-SASNEXTE/music |
|
| photo | /volume1/photo/2026 |
SYNC-pour_VPS/Sync-SASNEXTE/photo/2026 |
Année courante seulement |
| komga | /volume1/Komga |
SYNC-pour_VPS/Sync-SASNEXTE/Komga |
Non géré ici :
- Romans : abandonné
- Foxy : sur NAS Maison (pas sasnexte)
Options rclone — justifications
| Option | Rôle |
|---|---|
--delete-excluded |
Supprime sur kDrive les fichiers exclus qui auraient pu y être uploadés |
--ignore-errors |
Poursuit la sync si un fichier est inaccessible (NAS Synology parfois occupé) |
--delete-during |
Supprime les fichiers obsolètes au fil du scan, pas en fin de run |
--fast-list |
Réduit les appels API WebDAV (un seul listing récursif) |
@eaDir/** |
Dossiers de métadonnées Synology (miniatures) |
#recycle/** |
Corbeille Synology |
@__thumb/** |
Miniatures Synology |
*.@SynoResource / *.@SynoEAStream |
Flux de ressources étendues Synology |
--transfers=4 |
4 fichiers en parallèle — équilibre entre perf et charge WebDAV |
--checkers=8 |
8 vérifications de hash en parallèle |
--timeout=5m |
Timeout par opération I/O |
--contimeout=2m |
Timeout de connexion initiale |
Côté VPS — montages FUSE correspondants
Les services systemd sur le VPS montent les dossiers kDrive en FUSE :
| Service systemd | Point de montage | Source kDrive |
|---|---|---|
rclone-audiobookshelf.service |
/home/debian/audiobookshelf/audiobooks |
SYNC-pour_VPS/Sync-SASNEXTE/audiobooks |
kdrive-music.service |
/home/debian/music |
SYNC-pour_VPS/Sync-SASNEXTE/music |
rclone-photo.service |
/home/debian/photo |
SYNC-pour_VPS/Sync-SASNEXTE/photo |
kdrive-komga.service |
/home/debian/komga |
SYNC-pour_VPS/Sync-SASNEXTE/Komga |
Remote VPS : kdrive: — remote natif Infomaniak (@infomaniak/mcp-server-kdrive), compte julien.bertrand@live.fr, kDrive ID 591617.
Logs
- Un fichier de log par sync par run :
/volume1/homes/SAS_NEXTE/logs/sync_{nom}_{date}.log - Bilan global :
/volume1/homes/SAS_NEXTE/logs/sync_{date}.log - Commande de suivi :
tail -f /volume1/homes/SAS_NEXTE/logs/sync_music_*.log
REX déploiement 2026-06-23
- Problème 1 : CRLF dans le script (édition Windows) →
bash -xmontrait\rcomme commande inconnue. Fix : réécrire viavisur le NAS. - Problème 2 : mot de passe WebDAV périmé (401 Unauthorized) → régénéré le 2026-06-09 côté VPS mais pas mis à jour sur le NAS. Fix :
rclone config update kdrive_music pass $(rclone obscure MDP). - SSH bloqué : pare-feu NAS + 2FA rendent le SSH depuis l'extérieur inaccessible. Passer par une session SSH locale ou DSM.
- Résultat : 4 syncs validés — audiobooks 48.9 GiB / 23 min, music 1 GiB / 45s, photo et komga déjà à jour.
260727 - Claude en MCP sur le NASmaison
Le NASmaison est un petit Synology DS218j installé à la maison de Julien. IL sert surtout de stockage des livres et des films. Egalement des cartes rasters, le dossier personnel de Cécile, Elio et Zoée. IL a une copie miroir du dossier musique et komga, mais plus photos.
Il est synchronisé avec le NAS SASNEXTE pour musique et Komga.
Il compose au quotidien 6 procédures hyperbacups de la bibliothèque de livres en direction du Kdrive :
- les livres de Foxy répartis par grands thèmes
- les livres de la nouvelle bibliothèque - biblio-calibre
Claude a désormais une connexion MCP privilégiée sur le NASmaison. Et peut notamment garantir le transfert sécurisé des dossiers
260731-Claude et SASNEXTE sur le PC Elio+Jux
WireGuard sasnexte sur le PC Elio+Jux — diagnostic et résolution
Date : 2026-07-31 | Machine : PC Windows eliob | NAS cible : sasnexte (82.66.244.248)
Statut : RÉSOLU — tunnel activé, lecteur S: mappé sur \\10.0.0.2\NEXTE
Question initiale
WireGuard a été monté sur ce PC et sur le NAS sasnexte, mais le disque du NAS n'apparaissait pas comme lecteur dans l'explorateur de fichiers Windows. Pourquoi ?
Réponse courte
Deux causes cumulées :
- Le tunnel n'était pas activé sur le PC : la config
vps_maisonpc_sasnexteétait importée dans l'application WireGuard, mais jamais activée (aucun serviceWireGuardTunnel$*, aucun adaptateur réseau,wg showvide). - Un lecteur réseau ne se crée jamais tout seul : la découverte réseau Windows (broadcast/mDNS/WS-Discovery) ne traverse pas un tunnel de couche 3 — le NAS n'apparaîtra jamais spontanément dans « Réseau ». Il faut mapper manuellement une lettre avec
net use.
Topologie du tunnel vps_maisonpc_sasnexte
Réseau 10.0.0.0/24, hub-and-spoke avec le VPS Jux comme serveur (wg0, port UDP 51820) :
| IP | Machine | État (2026-07-31) |
|---|---|---|
| 10.0.0.1 | VPS Jux (51.77.141.54) — hub | Serveur, forwarding OK (ACCEPT in wg0 dans FORWARD) |
| 10.0.0.2 | NAS sasnexte (endpoint 82.66.244.248) | Connecté, handshake actif, 485 Gio transférés |
| 10.0.0.3 | PC Windows eliob | Connecté (après activation du tunnel) |
| 10.0.0.4 | PC maison (peer MkzKqDe…) |
Jamais connecté (pas d'endpoint) |
Clé publique serveur VPS : zbsY/bl4fHU1eR29PjTruK0Nrmp/BQORSlBGSh3Nkyo=
Diagnostic détaillé
Côté PC (avant activation)
- Application WireGuard installée, service
WireGuardManagerRunning - Config importée (dossier
C:\Program Files\WireGuard\Data\Configurationsprésent, chiffré DPAPI, admin uniquement) mais tunnel inactif - Aucun
.confen clair dans le profil utilisateur — pour l'exporter : app WireGuard en admin → « Exporter les tunnels »
Après activation du tunnel
- Adaptateur
vps_maisonpc_sasnexteUp, IP10.0.0.3/24 wg.exe showéchoue en non-admin (Permission denied) — normal, utiliserGet-NetAdapter/Get-NetIPAddresspour vérifier sans élévation- Piège ICMP : le NAS ne répond PAS au ping (pare-feu Synology) alors que le tunnel fonctionne. Ne pas diagnostiquer au ping — tester en TCP :
Test-NetConnection 10.0.0.2 -Port 445 - Ports NAS via tunnel : 445/139 (SMB) OK, 22 (SSH) OK, 5000/5001 (DSM) bloqués
SSH sasnexte depuis l'extérieur
Le SSH sas_nexte@82.66.244.248 (IP publique) refusait le mot de passe le 2026-07-31 alors que le même mot de passe fonctionne en SMB via le tunnel → le mot de passe est bon, c'est le SSH public qui est filtré (fail2ban/whitelist). Passer par le tunnel : ssh sas_nexte@10.0.0.2 (port 22 ouvert).
Résolution appliquée (2026-07-31)
- Tunnel activé dans l'app WireGuard (fait par Julien) → handshake OK avec le VPS
- Identifiants SMB enregistrés dans le gestionnaire d'identification Windows :
cmdkey /add:10.0.0.2 /user:sas_nexte /pass:"xAPIJU5108§" - Lecteur mappé :
net use S: \\10.0.0.2\NEXTE /persistent:yes - Vérifié :
S:liste bien le contenu du partage NEXTE
Important : le lecteur S: ne fonctionne que si le tunnel WireGuard est actif. Après un reboot, le tunnel se réactive automatiquement (service WireGuardTunnel$vps_maisonpc_sasnexte en démarrage auto) et Windows reconnecte S: grâce à /persistent:yes + identifiants cmdkey.
Partages SMB disponibles sur \10.0.0.2
ActiveBackupforBusiness, audiobooks, chat, home (dossier perso SAS_NEXTE), homes, Iso VM, music, NetBackup, NEXTE (mappé sur S:), Public_s, RAW, Ressources_NEXTE, retro, web, web_packages
Pour mapper un partage supplémentaire (les identifiants sont déjà enregistrés) :
net use R: \\10.0.0.2\Ressources_NEXTE /persistent:yes
Points ouverts
- Finaliser la config Ubuntu : exporter le
.confdepuis l'app WireGuard Windows (admin → Exporter les tunnels) — le peer 10.0.0.4 libre pourrait aussi servir pour Ubuntu - Identifier le peer 10.0.0.4 (
MkzKqDeVoIX9R9oMlCK7c76e3c3p/DJe/ryd0eqEV20=) : prévu pour le PC maison, jamais connecté
03_Claude et Ubuntu
01_Installation de Claude dans le Ubuntu
Contexte
Installation et configuration de Claude Code sur la machine Ubuntu 25.10 (utilisateur julien), avec synchronisation du dossier de travail via Syncthing.
1. Installation de Syncthing
Date : 2026-05-31
Système : Ubuntu 25.10 (questing)
Étapes
- Vérification : Syncthing absent des paquets installés
- Installation via les dépôts Ubuntu :
sudo apt install syncthing -y - Activation au démarrage :
systemctl --user enable --now syncthing - Interface web disponible sur :
http://127.0.0.1:8384
Résultat
Dossier synchronisé : /home/julien/Syncthing/
Contenu récupéré depuis le PC Windows (eliob) :
- Billets
- Jux_Obsidian
- Jux_univers (dont Claude-pcelio+jux/CLAUDE.md)
- Ouvrages
- PDF temps
- Suretés
- Tutoriels videos
2. Configuration de Claude Code
Le fichier CLAUDE.md de référence a été localisé dans le dossier synchronisé :
/home/julien/Syncthing/Jux_univers/Claude-pcelio+jux/CLAUDE.md
Ce fichier centralise toute la configuration : MCPs, credentials VPS, préférences, projets en cours. Il a été lu en début de session pour initialiser le contexte.
Mémoire Claude Code initialisée
Répertoire : /home/julien/.claude/projects/-home-julien/memory/
- user_profile.md — profil Julien/Jux/eliob
- project_vps.md — infrastructure VPS principal et Alteris
- reference_mcp.md — tous les services MCP et leurs credentials
- reference_syncthing.md — structure du dossier partagé
- feedback_preferences.md — style de réponse
3. Connexion BookStack depuis Ubuntu
Token API BookStack configuré manuellement pour permettre l écriture depuis Ubuntu (sans MCP npm disponible). Utilisation de l API REST directe via curl :
02_Diagnostic du Ubuntu par Claude
Diagnostic expert — Ubuntu julien-130430
Généré par Claude Code le 2026-05-31 à 19h57 — Ubuntu 25.10 questing — mis à jour 20h15
1. Système de base
| OS | Ubuntu 25.10 (questing) — version non-LTS, support jusqu'à juillet 2026 |
| Kernel | 6.17.0-19-generic (SMP PREEMPT_DYNAMIC — mars 2026) |
| Hostname | julien-130430 |
| Architecture | x86_64 |
| Uptime | 1h36 au moment du diagnostic |
| Langue | fr_FR.UTF-8 / shell bash |
2. Matériel
CPU
| Modèle | AMD Ryzen 5 2600X Six-Core Processor |
| Cœurs / Threads | 6 cœurs / 12 threads (1 socket) |
| Fréquence | 2200–3600 MHz (scaling à 99%) |
| Charge (1/5/15 min) | 2,44 / 1,98 / 1,17 — charge en train de baisser, acceptable |
RAM & Swap
| RAM totale | 15 Gi |
| RAM utilisée | 4,9 Gi utilisé + 9 Gi cache/tampon — 10 Gi disponibles |
| Swap | 4 Gi (fichier /swap.img), 5,5 Mi utilisés — quasi vide, bonne santé |
GPU
| Modèle | AMD Radeon RX 6400/6500 XT — Navi 24 (rev c1) |
| Driver | AMDGPU (open-source, intégré au kernel) |
| Monitoring | lm-sensors absent — pas de relevé de température possible |
3. Stockage
| Disque | Modèle | Taille | Partition | FS | Point de montage | Utilisé | Alerte |
|---|---|---|---|---|---|---|---|
| sda | SanDisk 3.2Gen1 (USB) | 57,3 G | sda2 | ext4 | / (racine) | 31G / 57G — 57% | |
| sdb | Patriot Burst (SSD) | 223,6 G | sdb3 | ntfs | /media/julien/CE1C8DC545 | 149G / 223G — 67% | |
| sdc | Seagate Backup Plus | 7,3 T | sdc2 | — | /media/julien/Seagate… | 3,1T / 7,3T — 42% | |
| sdd | — | 932 G | sdd1 | — | /media/julien/206897… | 827G / 932G — 89% | ⚠ Critique |
| sde | — | 932 G | sde2 | — | /media/julien/2ème disque dur | 294G / 932G — 32% |
Point d'attention : Le disque sdd1 est à 89% de capacité (827G/932G). Seuil critique à surveiller.
Note : Le système racine est sur une clé USB SanDisk (sda). Performances limitées par rapport à un SSD SATA ou NVMe. Risque de défaillance à long terme supérieur à un disque interne.
4. Réseau
| Interface | enp37s0 (Ethernet) |
| IP locale | 192.168.1.26/24 (DHCP) |
| IPv6 | 2a01:cb1c:833b:d00:2ef0:5dff:feec:62e0/64 |
| Passerelle | 192.168.1.1 |
| DNS | 192.168.1.1 + IPv6 routeur (via systemd-resolved) |
| DNSSEC | Désactivé (unsupported) |
| mDNS / LLMNR | Désactivés |
Recommandation : L'IP est attribuée par DHCP. Envisager une réservation DHCP fixe sur le routeur pour la stabilité de 192.168.1.26.
5. Services et sécurité
Services systemd
- 32 services actifs, 0 en échec — état sain
- Services notables : GDM (GNOME), NetworkManager, snapd, cups, bluetooth, chrony (NTP), avahi, rsyslog
- CUPS présent en double :
cups.service(paquet) etsnap.cups.cupsd.service(snap) — redondance inutile
SSH serveur
openssh-server absent — aucun accès SSH entrant possible sur cette machine. Si un accès distant est souhaité, installer openssh-server.
Pare-feu
ufw ne répond pas (non configuré ou inactif). La machine est probablement protégée par le NAT du routeur, mais aucune règle locale n'est en place.
Ports en écoute (accessibles depuis le réseau)
| Port | Service | Remarque |
|---|---|---|
| 22000/tcp+udp | Syncthing (PID 24179) | Sync P2P — normal |
| 53/tcp (127.0.0.53) | systemd-resolved | DNS local uniquement |
| 53/tcp (127.0.0.54) | systemd-resolved stub | DNS local uniquement |
Surface d'attaque réseau réduite : seul Syncthing écoute sur l'interface externe.
Sudo
Julien est membre du groupe sudo. La commande sudo -l nécessite un terminal interactif (PAM conversation) — normal dans le contexte Claude Code non-interactif.
6. Syncthing
| Processus | En cours d'exécution (PID 24179, port 22000 actif) |
| Service systemd | syncthing@julien.service : enabled / active ✓ (activé le 2026-05-31) |
| Dossiers synchronisés | Billets, Jux_Obsidian, Jux_univers, Ouvrages, PDF temps, Suretés, Tutoriels videos |
Fix 2026-05-31 : sudo systemctl enable --now syncthing@julien.service — service activé et démarré. Vérifié via API REST (HTTP 200, uptime ~17h).
7. Snaps
19 snaps installés. Plusieurs ont deux révisions montées simultanément (l'ancienne est conservée le temps du refresh par snapd) :
- Firefox (7901 + 7967), Thunderbird (1040 + 1073), Chromium (3375 + 3390)
- core20, core22, core24, gnome-42-2204, prompting-client, snapd-desktop-integration, firmware-updater, desktop-security-center
C'est le comportement normal de snapd (rollback possible). Les anciennes révisions sont supprimées automatiquement après quelques jours.
Nettoyage manuel possible : sudo snap set system refresh.retain=2 (déjà le défaut) ou snap list --all + sudo snap remove --revision=<rev> <snap>.
8. Environnements de développement
| Python | 3.13.7 (/usr/bin/python3) |
| Venv global | ~/.venv — activé automatiquement via .bashrc (configuré le 2026-05-31) |
| Paquets venv | psycopg2-binary 2.9.12, requests 2.34.2, httpx 0.28.1, pip 26.1.2 |
| Node.js | 24.16.0 |
| npm | 11.13.0 |
| Claude Code | v2.1.158 — installé et opérationnel |
| Docker | Non installé (ou non accessible sans sudo) |
Installation venv : nécessitait sudo apt install python3.13-venv (paquet absent par défaut sur Ubuntu 25.10).
Activation manuelle : source ~/.venv/bin/activate
9. Connexion PostgreSQL — alteris_geo
Testée et validée depuis Ubuntu le 2026-05-31 via le venv ~/.venv.
| Hôte | 79.137.14.202 (VPS Alteris) |
| Port | 5432 (accessible depuis l'extérieur) |
| Base | alteris_geo |
| Utilisateur | alteris_admin / Alteris2026 |
| Serveur | PostgreSQL 15.4 (Debian 15.4-1.pgdg110+1) — x86_64 |
| Table recherches | 4 entrées au 2026-05-31 (2 FreshRSS, 2 kDrive — toutes du 2026-05-29) |
Snippet de connexion Python (Ubuntu) :
import psycopg2
conn = psycopg2.connect(
host="79.137.14.202", port=5432,
dbname="alteris_geo", user="alteris_admin", password="Alteris2026"
)
10. Cron / tâches planifiées
- Pas de crontab utilisateur défini pour julien
- Tâches système présentes :
anacron,e2scrub_all,sysstat - Mises à jour automatiques :
unattended-upgrades.serviceactif
11. Logs / erreurs récentes
Les seules erreurs journalctl (niveau err) sur 7 jours sont des échecs PAM sudo en mode non-interactif (générés par ce diagnostic) + des warnings udev ALSA sans conséquence. Aucune erreur critique applicative.
Synthèse — Points d'action
| Priorité | Problème | Action recommandée | Statut |
|---|---|---|---|
| Haute | sdd1 à 89% (827G/932G) | Libérer de l'espace ou déplacer des données vers sde (32% utilisé) | En attente |
sudo systemctl enable syncthing@julien.service | ✓ Résolu 2026-05-31 | ||
| Moyenne | Système racine sur clé USB SanDisk | Envisager migration vers le SSD Patriot (sdb) pour fiabilité | En attente |
| Basse | Pare-feu inactif | sudo ufw enable + règles minimales si accès SSH ajouté | En attente |
| Basse | lm-sensors absent | sudo apt install lm-sensors && sudo sensors-detect | En attente |
| Basse | CUPS en double (paquet + snap) | Supprimer l'un des deux selon usage | En attente |
| Info | Ubuntu 25.10 non-LTS | Fin de support juillet 2026 — migration vers 26.04 LTS à lancer | En attente |
| Info | IP DHCP dynamique | Réservation DHCP 192.168.1.26 sur le routeur recommandée | En attente |
Points positifs
- 0 service systemd en échec
- Kernel récent (6.17.0, mars 2026)
- RAM bien dimensionnée (15 Gi, peu de swap utilisé)
- Surface réseau réduite (seul Syncthing exposé)
- Python 3.13 + venv opérationnel + connexion alteris_geo validée
- Node 24 LTS à jour
- Claude Code opérationnel
03_250531
1. Syncthing ne repartira pas automatiquement (service désactivé) — il faudra soit le lancer manuellement, soit profiter du redémarrage
pour faire sudo systemctl enable syncthing@julien.service avant d'éteindre.
✓ Fix 2026-05-31 : sudo systemctl enable --now syncthing@julien.service — service activé et démarré. Vérifié via API REST (HTTP 200, uptime ~17h).
2. Le venv ~/.venv se réactivera automatiquement via .bashrc à l'ouverture du terminal.
En attente — après mise à jour Ubuntu 26.04
Mise à jour Ubuntu 26.04 LTS
Lancée le 2026-05-31 via screen -S upgrade + sudo do-release-upgrade.
✓ Terminée — Ubuntu 26.04 LTS opérationnel.
Montage NAS (192.168.1.17) — partages foxy et video
Le NAS a changé d'IP : était sur 192.168.1.22, maintenant sur 192.168.1.17 (MAC Synology 00:11:32:9c:8e:c9 — attribution DHCP).
Script exécuté : sudo bash /home/julien/setup_nas.sh
✓ Terminé — foxy et video montés sur /mnt/nas/foxy et /mnt/nas/video.
Credentials : /etc/samba/credentials_nas — entrées fstab ajoutées avec options nofail,_netdev,x-systemd.automount.
Note : entrée WebDAV sasnexte (https://82.66.244.248:5006) corrigée dans fstab (typos : un seul slash et lettre 'o' dans le port).
✓ Signets Nautilus ajoutés : smb://juxjux@192.168.1.17, /mnt/nas/foxy, /mnt/nas/video dans ~/.config/gtk-3.0/bookmarks.
rclone — sauvegarde vers kDrive
Configuration perdue lors de la mise à jour Ubuntu 26.04. La tâche sauvegardait vers kDrive (WebDAV). À reconfigurer :
rclone config → type webdav, URL https://connect.drive.infomaniak.com, credentials compte Infomaniak.
Son Bluetooth — Xiaomi 15T Pro
Tentative d'utiliser le Xiaomi 15T Pro comme enceinte Bluetooth depuis Ubuntu. Impossible : le téléphone n'expose pas le profil Audio Sink (UUID 0000110b) en Bluetooth classique — il est uniquement Audio Source. Limitation firmware Xiaomi, non contournable en BT.
Alternative WiFi (SoundWire) possible mais peu pratique.
→ À faire : acheter un casque ou une enceinte Bluetooth. N'importe quel périphérique BT standard exposant le profil Audio Sink fonctionnera directement avec Ubuntu/PipeWire.
05_Claude et les MCP
Quelles opportunités entre logiciels opensource et les IA
Voici une liste des logiciels open source dans les domaines de l’infographie, la PAO, la CAO et la géomatique qui, en juin 2026, bénéficient d’une connexion MCP (Model Context Protocol) ou pour lesquels des serveurs MCP existent ou sont en développement pour permettre à une IA de prendre la main sur la production de documents ou d’automatiser des tâches.
📌 Logiciels compatibles MCP (ou avec serveurs MCP disponibles)
🎨 Infographie & PAO
-
Scribus Logiciel de PAO open source pour la mise en page professionnelle (brochures, magazines, livres). Statut MCP : Des serveurs MCP communautaires permettent d’interagir avec les fichiers Scribus (lecture, modification, export) via des scripts Python ou des connecteurs dédiés. Cela permet à une IA de générer ou modifier des mises en page automatiquement.
-
Inkscape Éditeur de graphiques vectoriels (SVG) open source. Statut MCP : Des serveurs MCP existent pour manipuler des fichiers SVG (création, édition, export) via des outils comme Puppeteer ou des scripts Python. Une IA peut ainsi générer ou modifier des visuels vectoriels.
-
GIMP Logiciel de retouche photo et de création graphique open source. Statut MCP : Des connecteurs MCP permettent d’automatiser des tâches de retouche ou de génération d’images via des scripts (Python, Bash) ou des API externes.
🏗️ CAO (Conception Assistée par Ordinateur)
-
FreeCAD Logiciel de CAO 3D paramétrique open source. Statut MCP : Des serveurs MCP permettent d’interagir avec les fichiers FreeCAD (
.FCStd) pour automatiser la création ou la modification de modèles 3D. Une IA peut ainsi générer des pièces ou des assemblages à partir de prompts textuels. -
Blender Logiciel open source de modélisation 3D, animation et rendu. Statut MCP : Blender est explicitement cité comme compatible avec MCP dans la documentation officielle. Des serveurs MCP permettent de contrôler Blender via Python (API Blender + MCP), ce qui permet à une IA de créer, modifier ou rendre des scènes 3D, ou même d’automatiser des workflows complexes (ex : génération de visuels pour l’architecture ou le design industriel).
-
OpenSCAD Logiciel de CAO 3D open source basé sur un langage de script. Statut MCP : Des serveurs MCP permettent d’exécuter des scripts OpenSCAD et de récupérer les modèles 3D générés, ce qui facilite l’automatisation de la conception paramétrique.
🌍 Géomatique (SIG & Cartographie)
-
QGIS Système d’Information Géographique (SIG) open source le plus répandu. Statut MCP : Des serveurs MCP permettent d’interagir avec QGIS via PyQGIS (Python) ou des API REST. Une IA peut ainsi :
- Charger des couches géospatiales (Shapefile, GeoJSON, etc.).
- Effectuer des analyses spatiales (requêtes, calculs de distances, etc.).
- Générer des cartes ou des rapports automatiques.
-
GRASS GIS SIG open source avancé pour l’analyse spatiale. Statut MCP : Compatible via des scripts Python ou des connecteurs MCP dédiés pour automatiser des traitements géomatiques (ex : classification d’images satellite, modélisation de terrains).
-
GDAL/OGR Bibliothèque open source pour la manipulation de données géospatiales (raster/vectoriel). Statut MCP : Des serveurs MCP permettent d’utiliser GDAL pour convertir, traiter ou analyser des données géospatiales (ex : transformation de formats, extraction de métadonnées).
-
PostGIS Extension spatiale pour PostgreSQL. Statut MCP : Des serveurs MCP permettent d’interroger des bases de données PostGIS en langage naturel (ex : "Trouve tous les bâtiments à moins de 500m d’une rivière") et de générer des rapports ou des cartes automatiques.
🔌 Comment ça marche ?
Le Model Context Protocol (MCP) est un standard ouvert créé par Anthropic et donné à la Linux Foundation en décembre 2025. Il permet à une IA (comme Claude, ChatGPT, ou des modèles locaux) de :
- Lire/écrire des fichiers (ex :
.svg,.fcstd,.qgs). - Exécuter des fonctions (ex : lancer un rendu dans Blender, une requête SQL dans PostGIS).
- Interagir avec des API externes (ex : Google Drive, GitHub, etc.).
Exemples concrets en 2026 :
- Un agent IA peut créer une carte thématique dans QGIS à partir d’une demande en langage naturel.
- Une IA peut générer un modèle 3D dans FreeCAD en suivant un cahier des charges textuel.
- Un workflow automatisé peut produire une affiche dans Scribus en combinant du texte généré par IA et des images retouchées via GIMP.
📂 Où trouver les serveurs MCP pour ces logiciels ?
- Registry officiel : GitHub MCP Servers (plus de 1 000 serveurs open source en 2026).
- Exemples de serveurs :
💡 Cas d’usage avancés
- Infographie : Génération automatique de visuels pour les réseaux sociaux (Inkscape + IA).
- PAO : Création de catalogues produits à partir d’une base de données (Scribus + MCP + PostGIS).
- CAO : Optimisation topologique de pièces mécaniques (FreeCAD + IA + MCP).
- Géomatique : Analyse de risques naturels à partir de données ouvertes (QGIS + GDAL + MCP).
⚠️ Limites et précautions
- Sécurité : MCP permet un accès profond aux outils. Il faut contrôler les permissions pour éviter des actions non désirées (ex : suppression de fichiers).
- Maturity : Tous les logiciels n’ont pas encore de serveurs MCP officiels, mais la communauté développe activement des connecteurs.
- Performances : Pour les logiciels lourds (Blender, QGIS), une machine puissante est recommandée pour éviter les lenteurs.
🔍 Pour aller plus loin
Question : Souhaites-tu que je te guide pour configurer un serveur MCP spécifique (ex : Blender ou QGIS) ou explorer un cas d’usage précis dans ton domaine ?
Retours de Claude et propositions d'intégration
Contexte
Analyse rédigée par Claude Code (Sonnet 4.6) le 2026-06-20, à partir d'une session de travail sur le PC Windows (eliob).
Logiciels utilisés par Julien : QGIS, Inkscape, GIMP, Scribus. Ces quatre outils forment un workflow cohérent : QGIS pour la donnée géospatiale, Inkscape et Scribus pour la mise en page cartographique et la PAO, GIMP pour le traitement d'image.
Note critique sur la page 227
La page 227 ("Quelles opportunités entre logiciels opensource et les IA") a vraisemblablement été générée par une IA en mode chatbot. Les liens GitHub vers modelcontextprotocol/servers/tree/main/src/servers/blender, .../qgis, .../freecad, .../postgis sont probablement hallusinés — ces sous-dossiers n'existent pas dans le dépôt officiel MCP. À vérifier systématiquement avant d'agir sur ces références.
Analyse par logiciel
QGIS — Priorité 1 (le plus mature et le plus pertinent)
Ce qui existe réellement : Le projet qgis-mcp (disponible sur GitHub, maintenu par la communauté) expose QGIS comme un serveur MCP local. Il s'installe comme un plugin Python dans QGIS et ouvre un socket local sur lequel Claude peut envoyer des commandes PyQGIS.
Capacités concrètes :
- Charger des couches (Shapefile, GeoJSON, WMS, PostGIS)
- Lancer des algorithmes de traitement (buffer, intersection, statistiques zonales)
- Modifier la symbologie d'une couche
- Exporter une carte en PNG/PDF
Avantage spécifique à Julien : La base PostGIS alteris_geo sur le VPS Alteris (79.137.14.202:5432) est déjà accessible. Un workflow QGIS + MCP + PostGIS permettrait à Claude de : interroger la base en SQL spatial → charger le résultat dans QGIS → générer une carte thématique → exporter en PDF, le tout en langage naturel.
Contrainte : QGIS doit être ouvert sur la machine locale. Le MCP communique via socket local (pas de pilotage à distance).
Scribus — Priorité 2 (fort potentiel pour les rendus cartographiques)
Ce qui existe réellement : Scribus expose une API Python complète via son module scribus (accessible en mode headless : scribus --python-script myscript.py). Pas de serveur MCP publié, mais un MCP custom est trivial à écrire : un script Python qui reçoit des commandes MCP et les traduit en appels scribus.*.
Capacités concrètes via Python headless :
- Créer un document depuis un gabarit
.sla - Injecter du texte dans des cadres de texte nommés
- Placer des images
- Exporter en PDF
Cas d'usage concret pour Julien : Générer automatiquement une fiche de synthèse cartographique (titre, carte exportée depuis QGIS, texte de légende) en combinant la carte produite par QGIS MCP et un gabarit Scribus.
Contrainte : Scribus headless est instable sur certaines versions — à tester avec la version installée. La génération de gabarits .sla de référence est un prérequis.
Inkscape — Priorité 3 (manipulation SVG, pas contrôle UI)
Ce qui existe réellement : Pas de serveur MCP dédié pour contrôler l'interface Inkscape. En revanche, deux approches sont réalistes :
- Manipulation directe du SVG — le format natif d'Inkscape est du XML/SVG standard. Claude peut générer ou modifier des fichiers SVG avec Python (
lxml,svgwrite) sans lancer Inkscape. - Inkscape CLI —
inkscape --actions="verb1;verb2"permet des opérations batch (export PNG/PDF, conversion de formats) pilotables depuis un MCP.
Cas d'usage concret pour Julien : Modifier programmatiquement une carte SVG exportée depuis QGIS (changer des couleurs, ajouter un texte, insérer un logo) avant intégration dans Scribus.
Contrainte : L'automatisation reste au niveau fichier, pas au niveau interactif. Pour un usage cartographique, QGIS couvre déjà la plupart des besoins de rendu.
GIMP — Priorité 4 (batch uniquement)
Ce qui existe réellement : GIMP peut être piloté en batch via gimp --no-interface --batch='(script-fu-batch-list ...)' ou via Python-Fu (gimp --batch). Un MCP custom est faisable.
Cas d'usage concret pour Julien : Traitement en masse d'images pour intégration dans des documents Scribus (redimensionnement, recadrage, conversion CMJN, compression). Moins critique si StirlingPDF couvre déjà les besoins de compression.
Contrainte : GIMP batch est lent au démarrage. Pour du traitement image simple, des alternatives Python (Pillow, ImageMagick) sont plus légères à wraper en MCP.
Proposition de workflow intégré
PostGIS (Alteris) ──→ QGIS MCP ──→ carte exportée (PNG/PDF)
│
▼
Inkscape CLI (ajustements SVG)
│
▼
Scribus headless (mise en page finale)
│
▼
StirlingPDF (compression)
Claude pilote l'ensemble de la chaîne : de la requête spatiale jusqu'au document final, sans intervention manuelle.
Ordre de priorité pour une mise en œuvre
| Priorité | Outil | Action | Effort |
|---|---|---|---|
| 1 | QGIS | Installer le plugin qgis-mcp, tester avec une couche PostGIS |
Faible |
| 2 | Scribus | Écrire un MCP custom Python headless, créer un gabarit .sla de référence |
Moyen |
| 3 | Inkscape | MCP de manipulation SVG via lxml + CLI export |
Faible |
| 4 | GIMP | MCP batch Python-Fu | Moyen (faible priorité) |
Recommandation : commencer par QGIS. C'est le maillon central du workflow de Julien, le MCP existe déjà, et la base PostGIS Alteris est immédiatement exploitable.
QGIS MCP
Références
- Plugin officiel : plugins.qgis.org/plugins/qgis_mcp_plugin — version 0.5.0, compatible QGIS 3.28–4.x
- Dépôt GitHub : nkarasiak/qgis-mcp — 102 outils MCP (couches, traitements, symbologie, export, mise en page/atlas, SQL cross-couches)
Architecture
Claude Code ↔ Serveur MCP Python (uvx) ↔ socket TCP local ↔ Plugin QGIS (dock "QGIS MCP")
Le plugin QGIS crée un serveur TCP local. Le serveur MCP Python (lancé par Claude Code via uvx) s'y connecte. QGIS doit être ouvert et le serveur démarré avant de lancer Claude Code.
Prérequis
Installer uv (gestionnaire de paquets Python) si absent :
winget install astral-sh.uv
Installation
1. Plugin dans QGIS
Extensions > Installer/Gérer les extensions > chercher QGIS MCP > Installer.
Redémarrer QGIS, puis cliquer Start Server dans le dock QGIS MCP.
2. Enregistrer le MCP dans Claude Code
claude mcp add -s user qgis -- uvx --from https://github.com/nkarasiak/qgis-mcp/archive/refs/heads/main.zip qgis-mcp-server
-s user = enregistrement global (tous les projets Claude Code).
3. Vérifier
Dans une session Claude Code avec QGIS ouvert et le serveur démarré, demander diagnose — confirme la synchronisation plugin/serveur MCP.
Ordre de démarrage (à chaque session)
- Ouvrir QGIS
- Cliquer Start Server dans le dock QGIS MCP
- Lancer Claude Code
Authentification (optionnel, machines partagées)
Définir QGIS_MCP_TOKEN=votre-secret dans l'environnement QGIS, redémarrer le serveur, puis ajouter la même variable à la config MCP :
"env": { "QGIS_MCP_TOKEN": "votre-secret" }
Capacités principales
| Catégorie | Exemples |
|---|---|
| Couches | Charger Shapefile, GeoJSON, WMS, PostGIS ; lister, supprimer |
| Traitements | Buffer, intersection, statistiques zonales (1000+ algorithmes) |
| Symbologie | Modifier couleurs, classification, étiquettes |
| Export | PNG, PDF, carte mise en page |
| SQL cross-couches | Requêtes spatiales directement depuis Claude |
| Mise en page/Atlas | Créer et exporter des atlas cartographiques |
Lien avec PostGIS Alteris
La base alteris_geo (79.137.14.202:5432, user alteris_admin) est directement utilisable depuis QGIS MCP : Claude peut interroger PostGIS en SQL spatial, charger le résultat comme couche QGIS, styliser et exporter en PDF — sans intervention manuelle.
Le port 5432 n'est pas exposé publiquement (pare-feu VPS). Connexion via tunnel SSH obligatoire (voir section Tunnel SSH).
Tunnel SSH vers PostGIS Alteris
Option 1 — Tunnel manuel (terminal externe)
Lancer avant QGIS/Claude Code :
ssh -L 5433:localhost:5432 debian@79.137.14.202 -N
Puis se connecter sur localhost:5433 au lieu de 79.137.14.202:5432.
Option 2 — Tunnel automatique via paramiko (PyQGIS) ✓ validé 2026-06-20
Ouvre le tunnel directement depuis la console Python QGIS, sans terminal externe.
Installation de paramiko (une seule fois)
sys.executable dans QGIS pointe sur qgis-bin.exe — subprocess est inutilisable. Utiliser pip en interne :
from pip._internal.cli.main import main as pip_main
pip_main(['install', 'paramiko'])
Paramiko s'installe dans C:\Users\eliob\AppData\Roaming\Python\Python312\site-packages (dossier utilisateur). QGIS ne l'inclut pas automatiquement dans sys.path — ajouter à chaque session :
import sys
sys.path.insert(0, r'C:\Users\eliob\AppData\Roaming\Python\Python312\site-packages')
import paramiko
print(paramiko.__version__) # 5.0.0
Script du tunnel (à lancer après l'import paramiko)
import socket
import threading
import select
class SSHTunnel(threading.Thread):
def __init__(self, ssh_host, ssh_user, ssh_password,
remote_port, local_port=5433, remote_host='127.0.0.1'):
super().__init__(daemon=True)
self.ssh_host = ssh_host
self.ssh_user = ssh_user
self.ssh_password = ssh_password
self.remote_host = remote_host
self.remote_port = remote_port
self.local_port = local_port
self._stop = threading.Event()
self.transport = None
self.server_sock = None
def run(self):
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(self.ssh_host, username=self.ssh_user, password=self.ssh_password)
self.transport = client.get_transport()
self.server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.server_sock.bind(('127.0.0.1', self.local_port))
self.server_sock.listen(5)
self.server_sock.settimeout(1.0)
print(f"[Tunnel] localhost:{self.local_port} → {self.ssh_host} → {self.remote_host}:{self.remote_port}")
while not self._stop.is_set():
try:
conn, _ = self.server_sock.accept()
threading.Thread(target=self._forward, args=(conn,), daemon=True).start()
except socket.timeout:
continue
self.server_sock.close()
client.close()
print("[Tunnel] Arrêté.")
def _forward(self, local_conn):
try:
chan = self.transport.open_channel(
'direct-tcpip',
(self.remote_host, self.remote_port),
local_conn.getpeername()
)
except Exception as e:
print(f"[Tunnel] Erreur canal : {e}")
local_conn.close()
return
while True:
r, _, _ = select.select([local_conn, chan], [], [], 5)
if local_conn in r:
data = local_conn.recv(4096)
if not data:
break
chan.send(data)
if chan in r:
data = chan.recv(4096)
if not data:
break
local_conn.send(data)
chan.close()
local_conn.close()
def stop(self):
self._stop.set()
tunnel = SSHTunnel('79.137.14.202', 'debian', 'RAW+NEXTE!', remote_port=5432, local_port=5433)
tunnel.start()
import time; time.sleep(1)
s = socket.socket(); s.settimeout(3)
try:
s.connect(('127.0.0.1', 5433)); print("Tunnel OK")
except Exception as e:
print(f"Tunnel KO : {e}")
finally:
s.close()
Pour arrêter : tunnel.stop()
Les avertissements DEPRECATION: Unexpected import of 'paramiko.*' sont inoffensifs (pip qui se plaint d'imports tardifs dans la même session).
Connexion PostGIS depuis PyQGIS
Charger une couche PostGIS
from qgis.core import QgsProject, QgsVectorLayer
uri = (
"host=localhost port=5433 dbname=alteris_geo "
"user=alteris_admin password=Alteris2026 sslmode=disable "
'table="altfoncier_28051"."28051_plu_zonage" (geom) sql='
)
layer = QgsVectorLayer(uri, "PLU Zonage 28051", "postgres")
QgsProject.instance().addMapLayer(layer)
Point clé — champ JSONB props
Les tables altfoncier ont leurs attributs métier dans un champ props de type JSONB. Dans PyQGIS, ce champ est un dict Python (pas une chaîne). Pour y accéder en expression QGIS :
map_get("props", 'typezone') ✓ correct
"props" LIKE '%typezone%' ✗ ne fonctionne pas (props n'est pas une chaîne)
Stylisation CNIG PLU (zonage)
Renderer catégorisé sur map_get("props", 'typezone') :
| typezone | Couleur remplissage | Couleur bordure | Label |
|---|---|---|---|
| U | #FFFF73 |
#A3A300 |
Zones urbaines |
| AU | #FFAA00 |
#CD6600 |
Zones à urbaniser |
| A | #D3FFBE |
#267300 |
Zones agricoles |
| N | #98E600 |
#267300 |
Zones naturelles et forestières |
from qgis.core import QgsCategorizedSymbolRenderer, QgsRendererCategory, QgsFillSymbol
cnig = {
'U': ('#FFFF73', '#A3A300', 'Zones urbaines (U)'),
'AU': ('#FFAA00', '#CD6600', 'Zones à urbaniser (AU)'),
'A': ('#D3FFBE', '#267300', 'Zones agricoles (A)'),
'N': ('#98E600', '#267300', 'Zones naturelles et forestières (N)'),
}
categories = []
for tz, (fill, border, label) in cnig.items():
symbol = QgsFillSymbol.createSimple({
'color': fill, 'outline_color': border, 'outline_width': '0.26'
})
categories.append(QgsRendererCategory(tz, symbol, label))
renderer = QgsCategorizedSymbolRenderer("map_get(\"props\", 'typezone')", categories)
layer.setRenderer(renderer)
layer.triggerRepaint()
Journal de session
2026-06-20 — Premier diagnostic validé
Première connexion réussie entre Claude Code et QGIS via MCP. Résultat du diagnose :
| Vérification | Résultat |
|---|---|
| QGIS | 4.0.3-Norrköping |
| Python | 3.12.13 |
| Qt | 6.11.0 |
| Plugin MCP | 0.5.0 (serveur et plugin synchronisés) |
| Clients connectés | 1 |
| Providers de traitement | 3d, gdal, grass, model, native, pdal, project, qgis, quickosm, script |
| Projet ouvert | Aucun (layer_count = 0) |
Statut global : healthy. Stack complète et opérationnelle.
2026-06-20 — Connexion PostGIS Alteris + stylisation CNIG
- Connexion PostGIS directe (
79.137.14.202:5432) → timeout (port filtré par pare-feu VPS) - Tunnel SSH manuel (
ssh -L 5433:localhost:5432 debian@79.137.14.202 -N) → connexion OK - Couche
altfoncier_28051.28051_plu_zonagechargée (20 entités, commune 28051) - Stylisation CNIG appliquée et validée visuellement
- Point clé découvert : le champ
props(JSONB PostGIS) arrive comme dict Python dans PyQGIS — utilisermap_get("props", 'typezone')en expression, pas LIKE sur chaîne
2026-06-20 — Tunnel paramiko validé
sys.executable=qgis-bin.exe→ subprocess inutilisable pour pip- Installation via
pip._internal.cli.main→ paramiko 5.0.0 installé dans le dossier utilisateur sys.path.insert(0, ...)nécessaire à chaque session (QGIS n'inclut pas le dossier utilisateur)- Tunnel paramiko démarré → Tunnel OK confirmé
- Couche PostGIS chargée via
localhost:5433→ succès
Prochaine étape :
- Exporter la carte en PDF via mise en page QGIS
Inkscape MCP
Vue d'ensemble
Inkscape est un éditeur de graphisme vectoriel open source basé sur le format SVG. À la différence de QGIS, il n'existe pas de plugin MCP officiel pour Inkscape en juin 2026 — mais plusieurs approches sont réalistes, avec des niveaux d'effort et de puissance différents.
Approches possibles
| Approche | Effort | Puissance | Statut |
|---|---|---|---|
| 1. Manipulation SVG directe | Aucun | Élevée (structure du fichier) | Fonctionne déjà |
| 2. MCP wrapper CLI Inkscape | Moyen (écrire un serveur MCP) | Moyenne (opérations CLI) | À construire |
| 3. Extension Inkscape + serveur TCP | Élevé (plugin Python Inkscape) | Maximale (GUI + rendu live) | À construire |
Approche 1 — Manipulation SVG directe (disponible maintenant)
SVG est du XML texte. Claude peut lire, écrire et modifier des fichiers .svg directement avec ses outils natifs, sans aucune intégration supplémentaire.
Ce que Claude peut déjà faire
- Lire la structure d'un SVG (éléments, attributs, groupes, calques Inkscape)
- Créer un SVG complet de zéro (formes, textes, chemins, dégradés)
- Modifier des propriétés : couleur, opacité, stroke, transform, viewBox
- Réorganiser les éléments dans l'arbre XML
- Ajouter/supprimer des calques (
<g inkscape:label="..." inkscape:groupmode="layer">) - Générer des motifs répétitifs, des grilles, des mises en page structurées
Limites de cette approche
- Pas de rendu live dans Inkscape — il faut rouvrir ou recharger le fichier
- Les opérations complexes (nœuds de chemin, boolean ops) sont difficiles à écrire à la main en SVG
- Pas d'accès aux filtres Inkscape (flou, ombres) via simple édition XML
Flux de travail type
Claude génère/modifie le .svg → tu recharges dans Inkscape (Ctrl+Z+rechargement) → ajustements manuels → boucle
Approche 2 — MCP wrapper CLI Inkscape
Inkscape expose une interface en ligne de commande (--actions) qui permet d'automatiser des opérations sans ouvrir l'interface graphique.
Commandes CLI Inkscape utiles
# Export PNG depuis SVG
inkscape --export-type=png --export-filename=sortie.png source.svg
# Export PDF
inkscape --export-type=pdf --export-filename=sortie.pdf source.svg
# Appliquer une transformation et exporter
inkscape --actions="select-all;object-set-attribute:transform,scale(2)" source.svg --export-type=svg --export-filename=sortie.svg
# Convertir texte en chemins
inkscape --actions="select-all;object-to-path" source.svg --export-type=svg --export-filename=sortie.svg
# Obtenir les dimensions du document
inkscape --query-all source.svg
Architecture d'un serveur MCP CLI
Claude Code ↔ Serveur MCP Python (stdio) ↔ subprocess inkscape CLI ↔ fichiers SVG/PNG/PDF
Un serveur MCP Python minimal exposerait des outils comme :
export_png(svg_path, output_path, dpi=96)export_pdf(svg_path, output_path)convert_text_to_paths(svg_path, output_path)get_document_dimensions(svg_path)apply_inkscape_action(svg_path, actions, output_path)
Prérequis
# Inkscape doit être dans le PATH
inkscape --version
# Inkscape 1.x.x (...)
Sur Windows, ajouter le dossier Inkscape au PATH système ou utiliser le chemin complet :
C:\Program Files\Inkscape\bin\inkscape.exe
Approche 3 — Extension Inkscape + serveur TCP (pattern QGIS)
La plus puissante mais la plus complexe à mettre en place. Inkscape supporte les extensions Python via le module inkex. Une extension pourrait ouvrir un socket TCP local et exposer des outils MCP (similaire au plugin QGIS MCP).
Architecture
Claude Code ↔ Serveur MCP Python (uvx) ↔ socket TCP local ↔ Extension Python Inkscape
Ce que ça permettrait
- Accéder aux éléments sélectionnés dans l'interface
- Appliquer des opérations live (boolean, nœuds, effets)
- Lire la position exacte des objets
- Déclencher des menus et actions Inkscape programmatiquement
Obstacles techniques
- Les extensions Inkscape s'exécutent en mode one-shot (lancées, exécutent, se ferment) — un serveur TCP persistant nécessite un thread daemon ou une extension de type "Effect" avec boucle
- L'API
inkexest bien documentée mais moins riche que PyQGIS - Aucun projet open source mature n'existe encore pour ce pattern (juin 2026)
Capacités envisageables selon l'approche
| Capacité | Approche 1 (SVG direct) | Approche 2 (CLI) | Approche 3 (Extension) |
|---|---|---|---|
| Créer des formes géométriques | ✓ | ✓ | ✓ |
| Modifier couleurs / styles | ✓ | ✓ | ✓ |
| Gérer les calques | ✓ | — | ✓ |
| Exporter PNG/PDF | — | ✓ | ✓ |
| Convertir texte en chemins | — | ✓ | ✓ |
| Boolean operations | — | ✓ (CLI) | ✓ |
| Lire sélection courante | — | — | ✓ |
| Appliquer filtres Inkscape | — | ✓ (partiel) | ✓ |
| Batch processing de fichiers | ✓ | ✓ | — |
| Rendu live dans l'UI | — | — | ✓ |
Cas d'usage concrets avec Inkscape
Avec l'approche 1 (maintenant)
- Générer des pictogrammes SVG (icônes, logos simples) à partir d'une description
- Créer des gabarits de mise en page (grilles, marges, zones de texte)
- Modifier en batch les couleurs d'une charte graphique sur plusieurs fichiers SVG
- Produire des cartes thématiques simplifiées à partir de données (ex : export QGIS → SVG → habillage Claude)
- Générer des diagrammes (organigrammes, schémas techniques) en SVG structuré
Avec l'approche 2 (à construire, effort ~2h)
- Pipeline : Claude génère SVG → CLI Inkscape exporte PDF → livraison automatique
- Batch conversion de SVG en PNG à différentes résolutions
- Optimisation SVG (texte en chemins avant impression)
Lien avec le workflow cartographique
Inkscape est souvent utilisé en aval de QGIS pour l'habillage cartographique (polices, mise en page avancée, symboles non gérés par QGIS). Le flux naturel serait :
QGIS MCP → export SVG → Claude (habillage Inkscape SVG direct) → Inkscape (retouches manuelles) → export PDF final
QGIS peut exporter une mise en page en SVG via Projet > Imprimer la mise en page > Exporter en SVG. Claude peut ensuite enrichir ce SVG (légendes, encadrés, pictogrammes) avant ouverture dans Inkscape.
Prochaine étape proposée
Trois options pour explorer concrètement :
- Test SVG direct — Claude génère un SVG d'exemple (carte, diagramme, gabarit) et tu l'ouvres dans Inkscape pour voir le résultat
- Prototype CLI MCP — écrire un serveur MCP Python minimal (~50 lignes) wrappant les exports Inkscape CLI, l'enregistrer dans Claude Code
- Exploration API inkex — ouvrir la console Python d'Inkscape et tester quelques commandes
inkexpour évaluer la faisabilité de l'approche 3
Mise en place réalisée (2026-07-21)
L'approche 2 (MCP wrapper CLI Inkscape) a été implémentée sur le PC Windows eliob.
Obstacle rencontré : version Microsoft Store (MSIX)
Le PC avait initialement Inkscape installé via le Microsoft Store, packagé en MSIX. Ce type de paquet s'est révélé inutilisable pour un pilotage CLI :
- L'exécutable dans
C:\Program Files\WindowsApps\...\inkscape.exerefuse l'exécution directe (Accès refusé) — ACL verrouillées par le sandboxing du paquet. - Aucun alias d'exécution (
AppExecutionAlias) n'est déclaré dans le manifest (AppxManifest.xml) — impossible d'appelerinkscapedepuis le PATH. Invoke-CommandInDesktopPackage(la seule méthode de lancement programmatique disponible) ouvre l'app en mode GUI sans retourner la main ni capturer stdout — inexploitable pour de l'automatisation headless (export,--actions, etc.).
Conclusion : les versions Inkscape installées via le Microsoft Store ne conviennent pas à un usage MCP/CLI. Il faut la version standalone.
Fix — installation de la version standalone
winget install --id Inkscape.Inkscape --source winget --accept-package-agreements --accept-source-agreements
- Package winget
Inkscape.Inkscape(distinct du Store) → installe dansC:\Program Files\Inkscape\bin\inkscape.exe - Version installée : 1.4.4 (dcaf3e7, 2026-05-05)
- Vérification :
& "C:\Program Files\Inkscape\bin\inkscape.exe" --versionrépond correctement, exit code 0
Important : si une version Store est déjà présente, la désinstaller d'abord (Paramètres > Applications, ou winget uninstall) pour éviter la confusion entre les deux installations.
Serveur MCP créé
- Fichier :
C:\Users\eliob\.claude\mcp_inkscape.py - Framework :
FastMCP(même pattern que les autres MCP du projet —mcp_portainer.py,mcp_jellyfin.py, etc.) - Constante :
INKSCAPE_EXE = r"C:\Program Files\Inkscape\bin\inkscape.exe"(chemin en dur — adapter si l'installation standalone se fait ailleurs)
Outils exposés :
| Outil | Rôle |
|---|---|
get_version() |
Vérifie qu'Inkscape répond (smoke test) |
get_document_dimensions(svg_path) |
Dimensions et bounding boxes de tous les objets (--query-all) |
export_png(svg_path, output_path="", dpi=96) |
Export PNG |
export_pdf(svg_path, output_path="") |
Export PDF |
convert_text_to_paths(svg_path, output_path="") |
Convertit les textes en chemins vectoriels |
apply_inkscape_action(svg_path, actions, output_path="") |
Échappatoire générique — chaîne d'actions Inkscape libre (; séparées) |
Toutes les fonctions retournent {ok, returncode, stdout, stderr} (+ output_path pour les exports) — pas d'exception levée sur échec CLI, le code retour renseigne l'appelant.
Enregistrement MCP
Ajouté dans C:\Users\eliob\.mcp.json :
"inkscape": {
"type": "stdio",
"command": "python",
"args": ["C:\\Users\\eliob\\.claude\\mcp_inkscape.py"],
"env": {}
}
Nécessite un rechargement de session Claude Code pour que le nouveau serveur MCP soit détecté et ses outils exposés.
Test réalisé
SVG de test (rectangle bleu + texte) → export_png → PNG de 1974 octets généré avec succès. get_document_dimensions retourne correctement les bounding box (svg1,10,10,180,80 etc.) via --query-all.
À reproduire demain sur le PC Windows Alteris
- Vérifier si Inkscape est installé via le Store (
Get-AppxPackage -Name "*Inkscape*") — si oui, désinstaller winget install --id Inkscape.Inkscape --source winget --accept-package-agreements --accept-source-agreements- Vérifier
C:\Program Files\Inkscape\bin\inkscape.exe --version - Copier
mcp_inkscape.py(script identique, cheminINKSCAPE_EXEà adapter si besoin) - Ajouter l'entrée
inkscapedans le.mcp.jsonde la machine Alteris - Recharger la session Claude Code et tester
get_version()+export_png()sur un SVG de test
Confirmation de fonctionnement (2026-07-21, session rechargée)
Après rechargement de la session Claude Code, le serveur MCP inkscape est bien détecté et ses 6 outils sont exposés. Tests effectués dans l'ordre :
| Test | Résultat |
|---|---|
get_version() |
OK — Inkscape 1.4.4 (dcaf3e7, 2026-05-05) |
get_document_dimensions(svg_path) sur un SVG de test (rect 80x80) |
OK — svg1,10,10,80,80 / rect1,10,10,80,80 |
export_png(svg_path) |
OK — PNG généré (389 octets), fichier vérifié sur disque |
Conclusion : le protocole MCP Inkscape est pleinement opérationnel sur le PC Windows eliob, de bout en bout (Claude Code → serveur MCP Python → subprocess Inkscape CLI → fichier de sortie).
LibreOffice MCP
quelles sont les possibilités MCP permises pour la suite logicielle LibreOffice pour interagir avec une IA - rédiger ou mettre à jour des paragraphes, controler le sens du texte,créer des tableurs, des présentations ?
En juin 2026, les possibilités offertes par le Model Context Protocol (MCP) pour interagir avec la suite LibreOffice (Writer, Calc, Impress, etc.) via une IA sont déjà bien avancées et permettent une intégration poussée. Voici ce que tu peux faire concrètement :
1. Édition et création de documents (Writer)
- Rédiger ou mettre à jour des paragraphes : Les serveurs MCP pour LibreOffice permettent à une IA de lire, écrire, modifier et formater des documents Writer (ODT). Tu peux demander à l'IA d'ajouter des titres, des paragraphes, des tableaux, des images, ou d'effectuer des recherches/remplacements automatiques dans le texte. Par exemple, un outil comme libreoffice-mcp ou Nelson MCP expose ces fonctionnalités via des appels d'outils standardisés.
- Contrôler le sens du texte : L'IA peut analyser le contenu, suggérer des reformulations, vérifier la cohérence ou la grammaire, et même générer du texte contextuel en fonction du document ouvert.
2. Gestion de tableurs (Calc)
- Créer et manipuler des tableurs : Les serveurs MCP permettent de créer, lire, modifier des feuilles de calcul (ODS), y compris la manipulation de cellules, l'insertion de formules, la création de graphiques, et l'automatisation de tâches répétitives (ex : mise à jour de données, tri, filtrage).
- Appeler une IA directement depuis une cellule : Certains projets, comme Nelson MCP, intègrent une fonction
=PROMPT()dans Calc, qui permet d'interroger une IA (ex : Claude, Gemini) directement depuis une formule Excel, pour générer des données ou des analyses en temps réel.
3. Présentations (Impress)
- Créer ou modifier des diapositives : Les outils MCP permettent d'automatiser la création de présentations, d'ajouter du texte, des images, des formes, ou de restructurer des diapositives existantes. L'IA peut aussi suggérer des mises en page ou du contenu en fonction d'un brief.
4. Automatisation et workflows
- Automatiser des workflows : Tu peux configurer des presets (ex : minimal, writer-edit, calc) pour exposer uniquement les outils nécessaires à ton agent IA. Par exemple, lancer un script qui génère un rapport dans Writer, extrait des données de Calc, et les insère dans une présentation Impress, le tout piloté par une IA.
- Intégration avec des clients MCP : Les serveurs MCP pour LibreOffice sont compatibles avec des clients comme Claude Desktop, Cursor, ou des outils personnalisés. Ils fonctionnent en local (via une extension LibreOffice ou un serveur HTTP) et permettent une interaction fluide entre l'IA et tes documents.
5. Exemples concrets d'outils
- libreoffice-mcp : Extension et serveur MCP pour LibreOffice, permettant une intégration complète avec des IA comme Claude ou Gemini. Fonctionne avec LibreOffice 24.2+ et expose une API HTTP pour les appels d'outils.
- Nelson MCP : Extension qui transforme tes documents LibreOffice en serveur MCP, avec des launchers intégrés pour Claude Code, Gemini CLI, etc. Permet de lire/éditer des documents ouverts et d'utiliser des fonctions avancées comme
=PROMPT()dans Calc. - OooDev : Bibliothèque Python qui simplifie l'accès à l'API UNO de LibreOffice, utilisée par plusieurs serveurs MCP pour manipuler des documents, des bases de données (Base), ou des graphiques.
6. Prérequis techniques
- LibreOffice 24.2 ou supérieur (pour la plupart des serveurs MCP).
- Installation d'une extension LibreOffice (ex :
libreoffice-mcp-extension.oxt) ou d'un serveur MCP local (Python/Node.js). - Connexion via socket (port 2083 ou 8765 selon les outils) ou HTTP pour les appels d'API.
7. Cas d'usage avancés
- Veille territoriale : Tu peux combiner MCP avec des alertes (ex : Google Alerts) et une IA pour filtrer, classer et résumer des informations dans des documents LibreOffice, comme tu l'envisageais pour ton projet de gestion de veilles.
- Gestion de bibliothèque : Automatiser la création de fiches ou de rapports à partir de tes données (ex : Kavita) en utilisant des templates Writer ou Calc.
Comment démarrer ?
- Installe un serveur MCP : Par exemple, Nelson MCP ou libreoffice-mcp.
- Configure ton client IA (Claude, Cursor, etc.) pour qu'il se connecte au serveur MCP.
- Ouvre un document LibreOffice et demande à ton IA de l'éditer ou de créer du contenu.
Modalités techniques de mise en place
Option retenue : Nelson MCP
Nelson MCP est l'option la plus directement compatible avec Claude Code — il expose un serveur MCP depuis LibreOffice via une extension .oxt, avec des launchers natifs pour Claude Code et Gemini CLI.
1. Installation de l'extension LibreOffice
- Télécharger l'extension depuis la page lobehub.com/mcp/quazardous-nelson-mcp (fichier
.oxt) - Dans LibreOffice : Outils → Gestionnaire des extensions → Ajouter → sélectionner le
.oxt - Redémarrer LibreOffice
2. Lancement du serveur MCP
Depuis LibreOffice via le menu dédié (Outils → Nelson MCP → Démarrer le serveur), ou en ligne de commande :
python3 -m nelson_mcp --port 8765
Le serveur écoute sur localhost:8765.
3. Configuration dans Claude Code
Ajouter dans C:\Users\eliob\.claude.json (section mcpServers du projet concerné) :
"libreoffice": {
"type": "http",
"url": "http://localhost:8765/mcp"
}
Si le serveur utilise stdio plutôt que HTTP :
"libreoffice": {
"type": "stdio",
"command": "python3",
"args": ["-m", "nelson_mcp"]
}
4. Points à vérifier lors de la mise en place
- Version LibreOffice :
libreoffice --version→ doit être ≥ 24.2 - Port 8765 libre :
netstat -ano | findstr 8765(Windows) - Un document LibreOffice doit être ouvert avant de lancer une requête MCP (le serveur nécessite un document actif)
- Tester avec une lecture simple du document ouvert pour valider la connexion
5. Alternative : libreoffice-mcp (KeithCu)
Si Nelson MCP pose problème, libreoffice-mcp (github.com/KeithCu/writeragent) expose une API HTTP via une extension .oxt sur le port 2083 :
"libreoffice": {
"type": "http",
"url": "http://localhost:2083"
}
Compétences Claude_QGIS
RAG de toutes les expériences de Claude dans l'utilisation de QGIS par MCP
REX 06079
Contexte
Affichage des IRIS de Mandelieu-la-Napoule (06079) depuis PostGIS Alteris, avec population graduée, étiquettes, fond orthophoto IGN Géoplateforme et cadastre vecteur WFS — entièrement piloté depuis Claude Code via le MCP QGIS, sans interaction manuelle dans QGIS.
Données utilisées
| Table / Source | Schéma / Provider | Contenu |
|---|---|---|
contours_iris_2025 |
insee_raw (PostGIS Alteris) |
Géométries IRIS France entière |
iris_2025_population |
insee_raw (PostGIS Alteris) |
Population 2022 par IRIS (recensement) |
| Orthophoto IGN | Géoplateforme (WMTS → XYZ) | HR.ORTHOIMAGERY.ORTHOPHOTOS — sans clé API |
| Cadastre parcelles | Géoplateforme WFS CADASTRALPARCELS.PARCELLAIRE_EXPRESS:parcelle |
Parcelles cadastrales vecteur — OGR driver |
Colonnes clés — pièges à retenir
contours_iris_2025 : colonnes standard sans espace — code_insee, code_iris, nom_iris, type_iris, geom
iris_2025_population : colonnes avec espace traînant (import INSEE brut) :
- Clé IRIS :
"IRIS "(avec espace) - Commune :
"COM "(avec espace) - Population totale 2022 :
"P22_POP "(avec espace) - Toutes les colonnes sont de type
text— caster en::numericavant usage
Résultats
9 IRIS pour 06079, population 2022 :
| code_iris | nom_iris | population |
|---|---|---|
| 060790101 | Zone d'activités | 24 |
| 060790102 | IRIS 2 | 2 701 |
| 060790103 | IRIS 3 | 2 000 |
| 060790104 | IRIS 4 | 3 058 |
| 060790105 | IRIS 5 | 2 197 |
| 060790106 | IRIS 6 | 2 432 |
| 060790107 | IRIS 7 | 3 188 |
| 060790108 | IRIS 8 | 2 944 |
| 060790109 | IRIS 9 | 2 656 |
Population min : 24 hab. (zone d'activités/naturelle) — max : 3 188 hab.
Cadastre : 26 439 parcelles après reprojection EPSG:4326 → EPSG:3857 (COUNT=2000 limite la requête WFS initiale à 2000 features, mais la reprojection en mémoire conserve toutes les géométries valides).
Procédure complète
Prérequis
Tunnel SSH paramiko actif (voir page 229 — Option 2). À relancer à chaque redémarrage de QGIS :
import sys
sys.path.insert(0, r'C:\Users\eliob\AppData\Roaming\Python\Python312\site-packages')
import paramiko
import socket, threading, select
class SSHTunnel(threading.Thread):
def __init__(self, ssh_host, ssh_user, ssh_password,
remote_port, local_port=5433, remote_host='127.0.0.1'):
super().__init__(daemon=True)
self.ssh_host = ssh_host; self.ssh_user = ssh_user
self.ssh_password = ssh_password; self.remote_host = remote_host
self.remote_port = remote_port; self.local_port = local_port
self._stop = threading.Event(); self.transport = None; self.server_sock = None
def run(self):
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(self.ssh_host, username=self.ssh_user, password=self.ssh_password)
self.transport = client.get_transport()
self.server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.server_sock.bind(('127.0.0.1', self.local_port))
self.server_sock.listen(5); self.server_sock.settimeout(1.0)
while not self._stop.is_set():
try:
conn, _ = self.server_sock.accept()
threading.Thread(target=self._forward, args=(conn,), daemon=True).start()
except socket.timeout:
continue
self.server_sock.close(); client.close()
def _forward(self, local_conn):
try:
chan = self.transport.open_channel('direct-tcpip',
(self.remote_host, self.remote_port), local_conn.getpeername())
except Exception:
local_conn.close(); return
while True:
r, _, _ = select.select([local_conn, chan], [], [], 5)
if local_conn in r:
data = local_conn.recv(4096)
if not data: break
chan.send(data)
if chan in r:
data = chan.recv(4096)
if not data: break
local_conn.send(data)
chan.close(); local_conn.close()
def stop(self):
self._stop.set()
tunnel = SSHTunnel('79.137.14.202', 'debian', 'RAW+NEXTE!', remote_port=5432, local_port=5433)
tunnel.start()
1. Charger l'orthophoto IGN (fond de carte)
Bug QGIS 4.0.3 : addMapLayer déclenche autoSelectAddedLayer → identifyMapTool → access violation quand une couche raster est ajoutée. Deux contournements obligatoires :
- Passer sur l'outil Pan avant d'ajouter la couche
- Utiliser
addMapLayer(layer, False)+root.insertLayer()(sans auto-sélection)
Format URI : le provider WMTS natif de QGIS (crs=...&layers=...&url=...) échoue sur la Géoplateforme (pas de capabilities). Solution : encoder l'URL WMTS en XYZ tiles avec {z}/{y}/{x}.
from qgis.core import QgsProject, QgsRasterLayer
from qgis.gui import QgsMapToolPan
from qgis.utils import iface
import urllib.parse
# 1. Passer sur Pan AVANT d'ajouter la couche raster (évite le crash identifyMapTool)
pan_tool = QgsMapToolPan(iface.mapCanvas())
iface.mapCanvas().setMapTool(pan_tool)
# 2. URI XYZ (le provider WMTS natif échoue sur data.geopf.fr)
base_url = (
"https://data.geopf.fr/wmts?SERVICE=WMTS&REQUEST=GetTile"
"&VERSION=1.0.0&LAYER=HR.ORTHOIMAGERY.ORTHOPHOTOS"
"&STYLE=normal&FORMAT=image/jpeg"
"&TILEMATRIXSET=PM&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}"
)
encoded = urllib.parse.quote(base_url, safe='')
uri = f"type=xyz&url={encoded}&zmin=0&zmax=19"
layer_ortho = QgsRasterLayer(uri, "Orthophoto IGN", "wms")
# 3. addToLegend=False + insertLayer manuel (évite autoSelectAddedLayer)
QgsProject.instance().addMapLayer(layer_ortho, False)
root = QgsProject.instance().layerTreeRoot()
root.insertLayer(-1, layer_ortho) # en bas de la pile
2. Créer la vue PostGIS et charger les IRIS
import psycopg2
conn = psycopg2.connect(host='localhost', port=5433, dbname='alteris_geo',
user='alteris_admin', password='Alteris2026')
cur = conn.cursor()
cur.execute("""
CREATE OR REPLACE VIEW insee_raw.v_iris_mandelieu_pop AS
SELECT c.fid, c.geom, c.nom_iris, c.code_iris,
ROUND(p."P22_POP "::numeric, 0)::integer AS population
FROM insee_raw.contours_iris_2025 c
LEFT JOIN insee_raw.iris_2025_population p ON p."IRIS " = c.code_iris
WHERE c.code_insee = '06079'
""")
conn.commit(); conn.close()
from qgis.core import QgsVectorLayer
uri = (
'host=localhost port=5433 dbname=alteris_geo '
'user=alteris_admin password=Alteris2026 sslmode=disable '
'table="insee_raw"."v_iris_mandelieu_pop" (geom) key=fid'
)
layer = QgsVectorLayer(uri, "IRIS Mandelieu-la-Napoule", "postgres")
3. Graduation par population (semi-transparent)
from qgis.core import QgsGraduatedSymbolRenderer, QgsRendererRange, QgsFillSymbol
colors = ['#EFF3FF', '#BDD7E7', '#6BAED6', '#2171B5', '#084594']
pmin, pmax = 24, 3188
step = (pmax - pmin) / 5
bounds = [pmin + i * step for i in range(6)]
ranges_def = []
for i in range(5):
lo, hi = bounds[i], bounds[i+1]
sym = QgsFillSymbol.createSimple({
'color': colors[i], 'outline_color': '#555555', 'outline_width': '0.3'
})
sym.setOpacity(0.6) # semi-transparent pour laisser voir l'ortho
ranges_def.append(QgsRendererRange(lo, hi, sym,
f"{int(lo):,}–{int(hi):,} hab.".replace(',', ' ')))
layer.setRenderer(QgsGraduatedSymbolRenderer('population', ranges_def))
4. Étiquettes + ajout dans le bon ordre
from qgis.core import (QgsPalLayerSettings, QgsTextFormat,
QgsTextBufferSettings, QgsVectorLayerSimpleLabeling)
from qgis.PyQt.QtGui import QColor, QFont
pal = QgsPalLayerSettings()
pal.fieldName = "concat(nom_iris, '\n', population, ' hab.')"
pal.isExpression = True
pal.placement = QgsPalLayerSettings.Placement.OverPoint
fmt = QgsTextFormat()
fmt.setFont(QFont("Arial", 8)); fmt.setSize(8); fmt.setColor(QColor('#1a1a1a'))
buf = QgsTextBufferSettings()
buf.setEnabled(True); buf.setSize(1); buf.setColor(QColor('white'))
fmt.setBuffer(buf); pal.setFormat(fmt)
layer.setLabelsEnabled(True)
layer.setLabeling(QgsVectorLayerSimpleLabeling(pal))
# IRIS en haut de la pile (index 0), ortho déjà en bas
QgsProject.instance().addMapLayer(layer, False)
root = QgsProject.instance().layerTreeRoot()
root.insertLayer(0, layer)
5. Zoomer sur Mandelieu
from qgis.core import QgsRectangle, QgsCoordinateReferenceSystem, QgsCoordinateTransform
src_crs = QgsCoordinateReferenceSystem("EPSG:4326")
dst_crs = QgsCoordinateReferenceSystem("EPSG:3857")
transform = QgsCoordinateTransform(src_crs, dst_crs, QgsProject.instance())
pt_min = transform.transform(6.87, 43.51)
pt_max = transform.transform(6.99, 43.60)
extent = QgsRectangle(pt_min.x(), pt_min.y(), pt_max.x(), pt_max.y())
iface.mapCanvas().setExtent(extent)
iface.mapCanvas().refresh()
6. Charger le cadastre (WFS vecteur)
Pièges :
- Le provider WFS natif QGIS est invalide sur
data.geopf.frpour ce typename → utiliser le driver OGR WFS - L'API Carto (
geo.api.gouv.fr) a timeout (appel synchrone dans le thread QGIS, 20 s) → abandonné - Le WFS retourne les données en EPSG:4326 mais le canevas est en EPSG:3857 → la couche apparaît dans le panneau mais n'est pas visible sur la carte → reproj obligatoire
import processing
from qgis.core import (QgsVectorLayer, QgsCoordinateReferenceSystem,
QgsFillSymbol, QgsSingleSymbolRenderer, QgsProject)
# Driver OGR WFS avec BBOX en paramètre URL (le provider WFS natif QGIS échoue)
url = (
"WFS:https://data.geopf.fr/wfs/ows?SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature"
"&TYPENAME=CADASTRALPARCELS.PARCELLAIRE_EXPRESS:parcelle"
"&BBOX=6.87,43.51,6.99,43.60,EPSG:4326&COUNT=2000"
)
layer_wfs = QgsVectorLayer(url, "Cadastre Mandelieu", "ogr")
# → isValid() = True, 2000 features, EPSG:4326
# Reprojection en mémoire EPSG:3857 (sinon couche invisible dans le canevas)
result = processing.run("native:reprojectlayer", {
'INPUT': layer_wfs,
'TARGET_CRS': QgsCoordinateReferenceSystem('EPSG:3857'),
'OUTPUT': 'memory:'
})
layer_cad = result['OUTPUT']
layer_cad.setName("Cadastre Mandelieu")
# → 26 439 features, EPSG:3857
# Symbologie : contour orange, remplissage quasi-transparent
sym = QgsFillSymbol.createSimple({
'color': '204,68,0,30', # orange très transparent (alpha 30/255)
'outline_color': '#CC4400',
'outline_width': '0.5'
})
layer_cad.setRenderer(QgsSingleSymbolRenderer(sym))
# Ajouter au-dessus des IRIS (index 0)
QgsProject.instance().addMapLayer(layer_cad, False)
root = QgsProject.instance().layerTreeRoot()
root.insertLayer(0, layer_cad)
Ordre final des couches (haut → bas) :
- Cadastre Mandelieu (vecteur WFS, EPSG:3857)
- IRIS Mandelieu-la-Napoule (PostGIS, gradué population)
- Orthophoto IGN (XYZ, fond)
Note cadastre : le BBOX rectangulaire déborde sur les communes voisines (Cannes à l'est, Pégomas au nord). Comportement attendu — pour restreindre au territoire communal strict, il faudrait une intersection post-chargement (pas de filtre code_commune disponible côté WFS Géoplateforme).
Points clés et pièges
| Sujet | Constat |
|---|---|
| Bug QGIS 4.0.3 — raster + identifyMapTool | addMapLayer sur une couche raster → access violation si l'outil Identifier est actif. Fix : passer sur Pan + addMapLayer(layer, False) + insertLayer() |
| Ne pas cliquer sur la couche raster dans le panneau | Même après ajout réussi, cliquer sur la couche raster dans le panneau des couches déclenche onActiveLayerChanged → crash. Rester sur l'outil Pan. |
| Provider WMTS natif QGIS invalide | crs=...&layers=...&url=https://data.geopf.fr/wmts → couche invalide. Fix : encoder en XYZ avec type=xyz&url=...{z}/{y}/{x} |
| Canvas au zoom mondial au démarrage | Les tuiles ne se chargent pas. Toujours zoomer sur la zone cible après ajout. |
| Provider WFS natif QGIS invalide | QgsVectorLayer(url, name, "WFS") → couche invalide pour CADASTRALPARCELS.PARCELLAIRE_EXPRESS:parcelle. Fix : driver OGR WFS QgsVectorLayer("WFS:https://...", name, "ogr") |
| API Carto timeout | geo.api.gouv.fr : appel HTTP synchrone dans le thread QGIS → 20 s de blocage puis timeout. Driver OGR WFS Géoplateforme préférable. |
| CRS mismatch WFS | WFS retourne EPSG:4326, canevas EPSG:3857 → couche présente dans le panneau mais invisible sur la carte. Fix : processing.run("native:reprojectlayer", ...) vers EPSG:3857 en mémoire. |
| Colonnes INSEE avec espace | "IRIS ", "COM ", "P22_POP " — espace traînant partout dans iris_2025_population |
| Types text | Toutes les valeurs numériques INSEE sont en text — caster avec ::numeric |
| Sous-requête URI QGIS | QgsDataSourceUri.setDataSource() sur-échappe les guillemets → couche invalide. Fix : créer une vue PostgreSQL |
sys.executable QGIS |
Pointe sur qgis-bin.exe — pip via subprocess inutilisable. Fix : pip._internal.cli.main |
sys.path paramiko |
QGIS n'inclut pas le dossier utilisateur Python. Ajouter sys.path.insert(0, ...) à chaque session |
Généralisation à d'autres communes
code_insee = '06079' # remplacer par le code cible
cur.execute(f"""
CREATE OR REPLACE VIEW insee_raw.v_iris_pop AS
SELECT c.fid, c.geom, c.nom_iris, c.code_iris, c.nom_commune,
ROUND(p."P22_POP "::numeric, 0)::integer AS population
FROM insee_raw.contours_iris_2025 c
LEFT JOIN insee_raw.iris_2025_population p ON p."IRIS " = c.code_iris
WHERE c.code_insee = '{code_insee}'
""")
Pour le cadastre, adapter le BBOX à l'emprise de la commune cible.
REX — 2026-06-21 (second run)
Résultat : 0 crash — procédure validée reproductible.
Run complet depuis un projet QGIS vide, piloté intégralement via MCP Claude Code → QGIS :
| Étape | Résultat |
|---|---|
| Tunnel SSH paramiko | OK — PostGIS Alteris accessible localhost:5433 |
| Orthophoto IGN (XYZ) | Valide — rendu fond de carte immédiat |
| Vue PostGIS + couche IRIS | 9 features, graduation 5 classes bleu, étiquettes population |
| Zoom sur Mandelieu | Cadrage correct EPSG:3857 |
| Cadastre WFS OGR + reprojection | 26 439 parcelles EPSG:3857, symbologie orange |
Conclusion : la procédure est stable et reproductible. Base solide pour une routine généralisable à n'importe quelle commune (code_insee + BBOX comme seuls paramètres variables). Potentiel : automatiser la production de fiches communales IRIS + cadastre + fond ortho à la demande depuis Claude Code.
Expertises Topologie - Claude et Qgis
Contexte PLU
Pour une couche de zones PLU topologiquement correcte, trois règles sont non-négociables :
- Pas de gaps — tout le territoire communal doit être couvert, sans trou entre zones
- Pas d'overlaps — une parcelle n'appartient qu'à une seule zone
- Géométries valides — pas de self-intersection, pas de géométrie nulle
Ces trois vérifications + corrections sont pilotables intégralement depuis Claude Code via le MCP QGIS, sans manipulation manuelle.
Bloc 1 — Configuration du snapping avant saisie
À lancer en début de session d'édition sur une couche PLU. Configure l'environnement QGIS pour que la saisie soit topologiquement propre dès le départ.
from qgis.core import QgsSnappingConfig, QgsTolerance, QgsProject
proj = QgsProject.instance()
snap_cfg = proj.snappingConfig()
snap_cfg.setEnabled(True)
snap_cfg.setMode(QgsSnappingConfig.SnappingMode.AllLayers)
snap_cfg.setType(QgsSnappingConfig.SnappingType.VertexAndSegment)
snap_cfg.setTolerance(10.0)
snap_cfg.setUnits(QgsTolerance.UnitType.Pixels)
snap_cfg.setIntersectionSnapping(True) # accrochage sur les intersections
proj.setSnappingConfig(snap_cfg)
proj.setTopologicalEditing(True) # partage de noeuds entre couches
proj.setAvoidIntersectionsMode(
QgsProject.AvoidIntersectionsMode.AvoidIntersectionsLayers
) # évite automatiquement les overlaps lors de la saisie
Paramètres clés :
| Paramètre | Valeur | Effet |
|---|---|---|
AllLayers |
mode | snap sur toutes les couches visibles |
VertexAndSegment |
type | accroche vertex ET bord |
10 px |
tolérance | adapté à la saisie courante PLU |
TopologicalEditing |
True | noeuds partagés entre polygones adjacents |
AvoidIntersectionsLayers |
mode | saisie d'un polygone qui "découpe" automatiquement ses voisins |
Piège : setType() attend QgsSnappingConfig.SnappingType — pas Qgis.SnappingType ni Qgis.SnappingTypes.
Bloc 2 — Audit topologique
Routine complète : validité + overlaps + gaps sur n'importe quelle couche polygone.
import processing
from qgis.core import QgsProject
def audit_topo(layer, unique_id='fid', gap_threshold=0, min_overlap_area=0):
"""
Audit topologique d'une couche polygone PLU.
Retourne un dict avec les couches d'erreurs et un résumé.
"""
rapport = {}
# 1. Validité géométrique (GEOS)
r_val = processing.run("native:checkvalidity", {
'INPUT_LAYER': layer, # NOTE : INPUT_LAYER, pas INPUT
'METHOD': 2, # GEOS
'IGNORE_RING_SELF_INTERSECTION': False,
'VALID_OUTPUT': 'memory:',
'INVALID_OUTPUT': 'memory:',
'ERROR_OUTPUT': 'memory:'
})
rapport['validite'] = {
'valides': r_val['VALID_COUNT'],
'invalides': r_val['INVALID_COUNT'],
'erreurs': r_val['ERROR_COUNT'],
'layer_invalides': r_val['INVALID_OUTPUT'],
'layer_erreurs': r_val['ERROR_OUTPUT']
}
# 2. Overlaps
r_ov = processing.run("native:checkgeometryoverlap", {
'INPUT': layer,
'UNIQUE_ID': unique_id,
'MIN_OVERLAP_AREA': min_overlap_area,
'TOLERANCE': 8,
'ERRORS': 'memory:',
'OUTPUT': 'memory:'
})
rapport['overlaps'] = {
'count': r_ov['ERRORS'].featureCount(),
'layer_errors': r_ov['ERRORS'],
'layer_features': r_ov['OUTPUT']
}
# 3. Gaps
r_gap = processing.run("native:checkgeometrygap", {
'INPUT': layer,
'UNIQUE_ID': unique_id,
'GAP_THRESHOLD': gap_threshold,
'TOLERANCE': 8,
'NEIGHBORS': 'memory:',
'ERRORS': 'memory:',
'OUTPUT': 'memory:'
})
rapport['gaps'] = {
'count': r_gap['OUTPUT'].featureCount(),
'layer_gaps': r_gap['OUTPUT'],
'layer_neighbors': r_gap['NEIGHBORS'], # requis pour fixgeometrygap
'layer_errors': r_gap['ERRORS']
}
# Résumé lisible
print(f"=== Audit topo : {layer.name()} ({layer.featureCount()} features) ===")
print(f"Validité : {rapport['validite']['valides']} OK / "
f"{rapport['validite']['invalides']} invalides")
print(f"Overlaps : {rapport['overlaps']['count']} erreur(s)")
print(f"Gaps : {rapport['gaps']['count']} trou(s)")
ok = (rapport['validite']['invalides'] == 0 and
rapport['overlaps']['count'] == 0 and
rapport['gaps']['count'] == 0)
print(f"Résultat : {'PROPRE' if ok else 'ERREURS DETECTEES'}")
return rapport
Usage :
from qgis.core import QgsProject
layer = QgsProject.instance().mapLayersByName("zones_plu")[0]
rapport = audit_topo(layer, unique_id='fid')
Piège critique : native:checkvalidity → paramètre INPUT_LAYER (pas INPUT). Erreur silencieuse sinon.
Bloc 3 — Correction automatique
S'appuie sur les couches d'erreurs produites par le Bloc 2.
3a. Corriger les overlaps
r_fix_ov = processing.run("native:fixgeometryoverlap", {
'INPUT': layer,
'ERRORS': rapport['overlaps']['layer_errors'],
'UNIQUE_ID': 'fid',
'OVERLAP_FEATURE_UNIQUE_IDX': 'gc_overlap_fid', # champ produit par checkgeometryoverlap
'ERROR_VALUE_ID': 'gc_error',
'OUTPUT': 'memory:',
'REPORT': 'memory:',
'TOLERANCE': 8
})
layer_corrige = r_fix_ov['OUTPUT']
print(f"Overlaps corrigés : {r_fix_ov['REPORT'].featureCount()} opérations")
3b. Combler les gaps
3 méthodes disponibles :
| Valeur | Méthode | Usage recommandé |
|---|---|---|
0 |
Ajouter à la plus longue bordure en commun | PLU — zone voisine qui partage le plus de frontière |
1 |
Créer une nouvelle entité | si le gap est une zone à part entière |
2 |
Ajouter à la plus grande zone voisine | quand la surface prime |
r_fix_gap = processing.run("native:fixgeometrygap", {
'INPUT': layer,
'NEIGHBORS': rapport['gaps']['layer_neighbors'], # issu de checkgeometrygap
'GAPS': rapport['gaps']['layer_gaps'],
'METHOD': 0, # 0 = plus longue bordure (recommandé PLU)
'UNIQUE_ID': 'fid',
'ERROR_ID_IDX': 'gc_errorid',
'OUTPUT': 'memory:',
'REPORT': 'memory:',
'TOLERANCE': 8
})
layer_sans_gap = r_fix_gap['OUTPUT']
print(f"Gaps comblés : {r_fix_gap['REPORT'].featureCount()} opérations")
3c. Corriger les géométries invalides (self-intersections, anneaux)
r_fix_val = processing.run("native:fixgeometries", {
'INPUT': rapport['validite']['layer_invalides'],
'METHOD': 1, # 1 = structure linéaire (robuste)
'OUTPUT': 'memory:'
})
layer_valide = r_fix_val['OUTPUT']
Bloc 4 — Accrochage post-saisie (snapgeometries)
Quand une couche a été saisie sans snapping actif, ou importée avec de micro-décalages entre polygones adjacents. Accroche les géométries d'une couche sur une couche de référence (ex : limites communales, autre zonage).
8 comportements disponibles :
| Valeur | Comportement | Usage |
|---|---|---|
0 |
Aligner les nœuds, ajoute sommets si besoin | défaut recommandé |
1 |
Point le plus proche, ajoute sommets | si nœuds mal alignés |
2 |
Aligner les nœuds, sans ajout de sommet | quand on veut conserver la densité |
4 |
Déplacer uniquement les extrémités (nœuds) | micro-corrections de bord |
6 |
Extrémités sur extrémités uniquement | lignes/filaires |
r_snap = processing.run("native:snapgeometries", {
'INPUT': layer_a_corriger,
'REFERENCE_LAYER': layer_reference,
'TOLERANCE': 0.5, # en unités de la couche (mètres si Lambert 93)
'BEHAVIOR': 0,
'OUTPUT': 'memory:'
})
layer_snapped = r_snap['OUTPUT']
Recommandation PLU : tolérance 0.1–0.5 m en EPSG:2154 (Lambert 93). Trop grande → déformation des géométries.
Bloc 5 — Reconstruction automatique depuis le cadastre
Quand une zone (ex : périmètre PLU, emprise de projet) a été saisie grossièrement et doit être recalée exactement sur les limites parcellaires cadastrales. Claude reconstruit le polygone par dissolution des parcelles qui chevauchent la zone rough ; l'opérateur complète ensuite manuellement les parties sans référence cadastrale (domaine public non-parcellaire : voiries, cours d'eau).
Validé le 2026-06-21 sur 06079-Minelle.gpkg (Mandelieu-la-Napoule) : 11 parcelles intersectantes → 2 retenues (overlap ≥ 50%) → 137 004 m², 31 nœuds, géométrie valide.
Principe
- Fixer les géométries du cadastre (WFS souvent invalide)
- Extraire les parcelles qui intersectent la zone rough
- Calculer le % de chevauchement pour chaque parcelle → garder celles à ≥ 50%
- Dissoudre → multiparttosingleparts → garder la plus grande part
- Écrire dans le GeoPackage en retirant d'abord les couches QGIS (file locking Windows)
Code complet
import processing
import urllib.parse
from qgis.core import (
QgsProject, QgsVectorFileWriter, QgsWkbTypes,
QgsFields, QgsMemoryProviderUtils
)
# Pré-requis : layer_cad (cadastre WFS reprojeté EPSG:3857)
# layer_zone (zone rough à recaler)
# gpkg_path (chemin du GeoPackage à écrire)
# 1. Fixer les géométries cadastrales (WFS Géoplateforme souvent invalide)
cad_fixed = processing.run("native:fixgeometries", {
'INPUT': layer_cad,
'METHOD': 1, # structure linéaire, robuste
'OUTPUT': 'memory:'
})['OUTPUT']
# 2. Extraire les parcelles qui intersectent la zone rough
parcelles_in = processing.run("native:extractbylocation", {
'INPUT': cad_fixed,
'PREDICATE': [0], # intersects
'INTERSECT': layer_zone,
'OUTPUT': 'memory:'
})['OUTPUT']
# 3. Calculer le % de chevauchement et retenir celles ≥ 50%
geom_zone = next(layer_zone.getFeatures()).geometry()
a_inclure = []
for f in parcelles_in.getFeatures():
inter = f.geometry().intersection(geom_zone)
pct = inter.area() / f.geometry().area() * 100
if pct >= 50:
a_inclure.append(f['gid'])
print(f"{parcelles_in.featureCount()} parcelles intersectantes → "
f"{len(a_inclure)} retenues (overlap ≥ 50%)")
print(f"GIDs retenus : {a_inclure}")
# 4. Sélectionner + dissoudre
ids_str = ', '.join(str(i) for i in a_inclure)
parcelles_sel = processing.run("native:extractbyexpression", {
'INPUT': cad_fixed,
'EXPRESSION': f'"gid" IN ({ids_str})',
'OUTPUT': 'memory:'
})['OUTPUT']
dissolved = processing.run("native:dissolve", {
'INPUT': parcelles_sel,
'FIELD': [],
'SEPARATE_DISJOINT': False,
'OUTPUT': 'memory:'
})['OUTPUT']
# 5. Single part → garder la plus grande
single = processing.run("native:multiparttosingleparts", {
'INPUT': dissolved,
'OUTPUT': 'memory:'
})['OUTPUT']
largest = max(single.getFeatures(), key=lambda f: f.geometry().area())
print(f"Résultat : {largest.geometry().area():.0f} m², "
f"{largest.geometry().constGet().nCoordinates()} nœuds")
layer_main = QgsMemoryProviderUtils.createMemoryLayer(
"main", QgsFields(), QgsWkbTypes.Type.Polygon, single.crs()
)
layer_main.dataProvider().addFeature(largest)
# 6. Écrire dans le GeoPackage
# CRITIQUE : retirer toutes les couches QGIS référençant le fichier avant écriture
for name in ["06079-Minelle"]:
for lyr in QgsProject.instance().mapLayersByName(name):
QgsProject.instance().removeMapLayer(lyr)
options = QgsVectorFileWriter.SaveVectorOptions()
options.driverName = "GPKG"
options.layerName = "06079-Minelle"
options.actionOnExistingFile = QgsVectorFileWriter.ActionOnExistingFile.CreateOrOverwriteLayer
# writeAsVectorFormatV3 retourne un tuple de 4 valeurs
res = QgsVectorFileWriter.writeAsVectorFormatV3(
layer_main, gpkg_path, QgsCoordinateTransformContext(), options
)
# res = (error_code, error_message, filename, layername)
if res[0] == 0:
print(f"Écrit : {gpkg_path} → couche '{options.layerName}'")
else:
print(f"ERREUR {res[0]} : {res[1]}")
# 7. Recharger dans QGIS pour vérification
layer_reload = QgsVectorLayer(
f"{gpkg_path}|layername={options.layerName}",
options.layerName, "ogr"
)
QgsProject.instance().addMapLayer(layer_reload, False)
root = QgsProject.instance().layerTreeRoot()
root.insertLayer(0, layer_reload)
iface.mapCanvas().setExtent(layer_reload.extent())
iface.mapCanvas().refresh()
print("Couche rechargée et zoomée.")
Pièges spécifiques
| Sujet | Constat |
|---|---|
writeAsVectorFormatV3 retourne 4 valeurs |
(error_code, error_message, filename, layername) — pas 2. Déstructurer en conséquence. |
| File locking Windows | QGIS garde un handle sur le fichier GeoPackage. Retirer toutes les couches référençant le fichier avec removeMapLayer() avant d'écrire. |
CreateOrOverwriteLayer pas CreateOrOverwriteFile |
CreateOrOverwriteFile supprime tout le fichier (détruisant les autres couches). CreateOrOverwriteLayer ne touche qu'à la couche cible. |
native:savefeatures échoue si fichier existe |
"A file system object already exists" — utiliser writeAsVectorFormatV3 à la place. |
MultiPolygon → asPolygon() fail |
Si les parcelles retenues ne sont pas adjacentes, le dissolve produit un MultiPolygon. Appliquer multiparttosingleparts + max(..., key=lambda f: f.geometry().area()) pour garder la plus grande part. |
| Cadastre WFS invalide | La Géoplateforme retourne parfois des géométries invalides (ex : feature 15026). Toujours fixer avec native:fixgeometries METHOD=1 avant usage comme couche de référence. |
Workflow collaboratif
Claude reconstruit le périmètre sur les limites parcellaires exactes. L'opérateur complète manuellement les parties manquantes non-parcellaires (domaine public : voiries, cours d'eau, espaces naturels non cadastrés). Les deux résultats sont complémentaires : la précision automatique sur le cadastre + le jugement humain sur le hors-cadastre.
Routine principale — Audit + Rapport
Fonction complète prête à l'emploi. Appeler par Claude en une seule commande.
import processing
from qgis.core import QgsProject, QgsSnappingConfig, QgsTolerance
def configurer_snapping_plu():
proj = QgsProject.instance()
snap_cfg = proj.snappingConfig()
snap_cfg.setEnabled(True)
snap_cfg.setMode(QgsSnappingConfig.SnappingMode.AllLayers)
snap_cfg.setType(QgsSnappingConfig.SnappingType.VertexAndSegment)
snap_cfg.setTolerance(10.0)
snap_cfg.setUnits(QgsTolerance.UnitType.Pixels)
snap_cfg.setIntersectionSnapping(True)
proj.setSnappingConfig(snap_cfg)
proj.setTopologicalEditing(True)
proj.setAvoidIntersectionsMode(
QgsProject.AvoidIntersectionsMode.AvoidIntersectionsLayers)
print("Snapping PLU configuré")
def audit_topo(layer, unique_id='fid', gap_threshold=0, min_overlap_area=0):
r_val = processing.run("native:checkvalidity", {
'INPUT_LAYER': layer, 'METHOD': 2,
'IGNORE_RING_SELF_INTERSECTION': False,
'VALID_OUTPUT': 'memory:', 'INVALID_OUTPUT': 'memory:', 'ERROR_OUTPUT': 'memory:'
})
r_ov = processing.run("native:checkgeometryoverlap", {
'INPUT': layer, 'UNIQUE_ID': unique_id,
'MIN_OVERLAP_AREA': min_overlap_area, 'TOLERANCE': 8,
'ERRORS': 'memory:', 'OUTPUT': 'memory:'
})
r_gap = processing.run("native:checkgeometrygap", {
'INPUT': layer, 'UNIQUE_ID': unique_id,
'GAP_THRESHOLD': gap_threshold, 'TOLERANCE': 8,
'NEIGHBORS': 'memory:', 'ERRORS': 'memory:', 'OUTPUT': 'memory:'
})
rapport = {
'layer': layer,
'unique_id': unique_id,
'validite': {
'valides': r_val['VALID_COUNT'],
'invalides': r_val['INVALID_COUNT'],
'layer_invalides': r_val['INVALID_OUTPUT']
},
'overlaps': {
'count': r_ov['ERRORS'].featureCount(),
'layer_errors': r_ov['ERRORS'],
'layer_features': r_ov['OUTPUT']
},
'gaps': {
'count': r_gap['OUTPUT'].featureCount(),
'layer_gaps': r_gap['OUTPUT'],
'layer_neighbors': r_gap['NEIGHBORS'],
'layer_errors': r_gap['ERRORS']
}
}
ok = (r_val['INVALID_COUNT'] == 0 and
r_ov['ERRORS'].featureCount() == 0 and
r_gap['OUTPUT'].featureCount() == 0)
print(f"\n=== Audit topo : {layer.name()} ===")
print(f" Géométries invalides : {r_val['INVALID_COUNT']}")
print(f" Overlaps : {r_ov['ERRORS'].featureCount()}")
print(f" Gaps : {r_gap['OUTPUT'].featureCount()}")
print(f" => {'PROPRE' if ok else 'ERREURS — voir rapport'}")
return rapport
# Usage type
# layer = QgsProject.instance().mapLayersByName("zones_plu")[0]
# configurer_snapping_plu()
# rapport = audit_topo(layer)
Pièges à retenir
| Sujet | Constat |
|---|---|
INPUT_LAYER vs INPUT |
native:checkvalidity exige INPUT_LAYER, tous les autres utilisent INPUT. Erreur silencieuse sinon. |
QgsSnappingConfig.SnappingType |
setType() attend ce type précis — pas Qgis.SnappingType ni Qgis.SnappingTypes. |
| NEIGHBORS obligatoire pour fixgeometrygap | La couche NEIGHBORS produite par checkgeometrygap doit être conservée et passée à fixgeometrygap. |
| Tolérance snapgeometries en unités couche | Si la couche est en Lambert 93 (mètres), 0.5 = 50 cm. Ne pas confondre avec la tolérance en pixels du snapping canvas. |
| METHOD 0 pour PLU gaps | "Plus longue bordure en commun" est la méthode la plus cohérente pour les zonages PLU (le gap va à la zone avec laquelle il partage le plus de frontière). |
| AvoidIntersectionsLayers | Mode le plus adapté PLU — évite les overlaps lors de la saisie mais uniquement sur les couches cochées dans les paramètres du projet. |
writeAsVectorFormatV3 retourne 4 valeurs |
(error_code, error_message, filename, layername) — pas 2. |
| File locking GeoPackage Windows | Retirer toutes les couches QGIS référençant le fichier avant écriture, utiliser CreateOrOverwriteLayer. |
Statut
- Validé le 2026-06-21 : Blocs 1–5 testés sur QGIS 4.0.3 via MCP Claude Code.
- Bloc 1 : snapping PLU
- Bloc 2 :
checkvalidity,checkgeometryoverlap,checkgeometrygap - Bloc 5 : reconstruction
06079-Minelle.gpkgdepuis cadastre WFS → 137 004 m², 31 nœuds, valide
- À tester :
fixgeometryoverlap,fixgeometrygap,snapgeometriessur une vraie couche PLU avec erreurs.
Competences Claude Libre Office
04_Claude et le PC Windows Elio+Jux
260803-suivi des logs de dysfonctionnement du PC - écrans bleus de la mort
Suivi des dysfonctionnements du PC eliob — écrans bleus
Machine : PC Windows eliob (pcelio)
Analyse initiale : 2026-08-03 — Claude Code
Fenêtre observée : 29/10/2025 → 03/08/2026 pour le journal d'événements (Windows réinstallé le 28/10/2025) — les compteurs SMART, eux, couvrent toute la vie des disques
En bref
- Deux problèmes distincts, pas un seul.
- Écrans bleus
0x50: cause établie —amdfendr.sys(AMD Crash Defender), embarqué dans un pilote Radeon de janvier 2022 jamais mis à jour. Confirmé par trois déterminations indépendantes, mécanisme du plantage compris. Correctif : réinstaller le pilote AMD avec DDU.- 30 coupures sèches sans écran bleu : cause inconnue. Aucune trace exploitable. Le compteur SMART montre que le phénomène précède la réinstallation de Windows — piste matérielle, alimentation en tête.
- Aucun composant électronique défectueux identifié à ce jour : 0 erreur WHEA, 4 disques SMART impeccables, SSD système à 88 % de vie restante.
- Actions déjà appliquées : voir §10. Action restante à la charge de Julien : réinstallation du pilote AMD.
Mise à jour du 2026-08-03, 08h30 — après élévation de privilèges, les rapports WER ont pu être lus et désignent nommément le module fautif :
amdfendr.sys(AMD Crash Defender). Le pilote réseau VirtualBox, suspect n°1 de la première version de cette analyse, est disculpé comme cause des écrans bleus. Voir §6.Mise à jour du 2026-08-03, 09h00 — WinDbg et smartmontools installés. Le vidage mémoire a été analysé : la pile d'appels confirme
amdfendr.syset donne le mécanisme exact du plantage (§6.1). Les données SMART complètes des 4 disques ont été relevées : aucun n'est défaillant, mais le compteur d'arrêts brutaux du SSD système révèle que l'instabilité est bien antérieure à la réinstallation de Windows (§7).
1. Configuration matérielle
| Élément | Valeur |
|---|---|
| Carte mère | MSI A320M-A PRO (MS-7C51), BIOS AMI 1.40 du 08/12/2020 |
| Processeur | AMD Ryzen 5 2600X — 6 cœurs, 3,6 GHz |
| Carte graphique | AMD Radeon RX 6500 XT (4 Go) — pilote 30.0.14023.3004 du 18/01/2022, soit 4 ans et demi de retard |
| Mémoire | 1 seule barrette 16 Go TEAMGROUP UD4-2666 (DIMM 0, canal B) — cadencée à 2400 MHz (sous sa fréquence nominale de 2666) |
| Disque système | SSD SATA Patriot Burst 240 Go (C: — 71 Go libres) |
| Disque secondaire | HDD SATA Toshiba HDWD110 1 To (D:) |
| Périphériques USB | ASMT 2115 1 To (E:), Seagate Backup+ Hub 8 To (F:), SanDisk 3.2Gen1 64 Go |
| OS | Windows 10 Famille 22H2 — build 19045, installé le 28/10/2025 |
| Boîtier / assemblage | Megaport, modèle 130430 |
Remarque sur l'âge : Julien évalue le PC à 9 ans d'usage intensif. Le Ryzen 2600X date de 2018 et la carte A320M-A PRO de 2019-2020 — le cœur de la machine a donc plutôt 6-7 ans. Le boîtier, l'alimentation et les ventilateurs peuvent être plus anciens s'ils ont été repris d'une configuration précédente. L'alimentation n'a pas pu être identifiée par logiciel — c'est une information à relever physiquement (marque, modèle, wattage, année), elle est déterminante pour la suite du diagnostic.
2. Méthode
Sources exploitées
Sans privilèges particuliers :
- Journal
System—Kernel-Power 41(arrêt inattendu),BugCheck 1001(code d'erreur BSOD),WHEA-Logger(erreurs matérielles remontées par le firmware),volmgr,Ntfs,disk - Propriétés internes des événements 41 (
BugcheckCode,BugcheckParameter1,PowerButtonTimestamp) — ce sont elles qui permettent de distinguer un vrai BSOD d'une coupure sèche - Corrélation temporelle événement par événement (dernier événement journalisé avant chaque redémarrage, présence ou non d'un arrêt propre
1074/13) - Inventaire matériel WMI/CIM, configuration d'alimentation et de vidage mémoire, dates et versions des pilotes tiers
Avec élévation (c'est ce qui a permis d'aboutir) :
- Rapports WER (
C:\ProgramData\Microsoft\Windows\WER\ReportArchive) — contiennent le classement de la panne par Microsoft - Mini-vidages (
C:\Windows\Minidump) etMEMORY.DMP - SMART complet des disques via
smartctl
Outils installés le 2026-08-03
| Outil | Version | Usage |
|---|---|---|
smartmontools |
7.5 | C:\Program Files\smartmontools\bin\smartctl.exe — SMART réel, à lancer en administrateur |
Microsoft.WinDbg |
1.2606 | Expose de vrais alias console dans %LOCALAPPDATA%\Microsoft\WindowsApps : cdbX64.exe, kdX64.exe, WinDbgX.exe |
Analyse d'un vidage en ligne de commande :
cdbX64.exe -z dump.dmp -y "srv*C:\symbols*https://msdl.microsoft.com/download/symbols" -c "!analyze -v; q" -logo sortie.txt
Trois points de méthode qui ont compté
- Les événements
41et1001sont horodatés au redémarrage suivant, pas à l'instant du crash. Le redémarrage automatique étant activé (AutoReboot=1), les deux coïncident à la minute près pour les BSOD — mais il ne faut jamais lire ces horodatages comme « l'heure de la panne » sans cette vérification. - Une corrélation temporelle, même serrée, ne vaut pas une preuve. Trois crashes à 12 secondes d'une erreur
VBoxNetLwfm'ont fait désigner le mauvais coupable. Seule la lecture du vidage a tranché. - Les preuves les plus utiles sont derrière une élévation de privilèges. Tant qu'on lit le journal en session standard, on tourne autour du problème.
3. Chiffres clés
| Indicateur | Valeur |
|---|---|
Arrêts anormaux (Kernel-Power 41) |
45 en 9 mois |
| dont écrans bleus réels (avec code bugcheck) | 15 (33 %) |
dont coupures sèches sans BSOD (BugcheckCode = 0) |
30 (67 %) |
Erreurs matérielles WHEA-Logger |
0 |
| Erreurs disque / NTFS critiques (90 j) | 2 Ntfs 50, 3 volmgr 161 (échec d'écriture du dump) |
| Bouton d'alimentation maintenu (arrêt forcé manuel) | 1 seul cas — 20/05/2026 20:35 |
Arrêt propre demandé (1074/13) juste avant le crash |
0 cas sur 45 |
| Arrêts brutaux au compteur SMART du SSD système | 146 pour 1 066 mises sous tension (13,7 %) |
Fréquence : environ 1 arrêt anormal tous les 6 jours en moyenne, avec des grappes (2 crashes le même jour à 5 reprises).
Écart entre les deux compteurs : 146 arrêts brutaux au SMART contre 45 dans le journal Windows. La centaine manquante est antérieure à la réinstallation du 28/10/2025 — voir §7.
4. Deux populations de pannes bien distinctes
Population A — 30 coupures sèches, sans écran bleu (67 %)
BugcheckCode = 0, PowerButtonTimestamp = 0 : le système s'est arrêté sans produire de vérification d'erreur, sans que le bouton d'alimentation ait été maintenu, et sans qu'un arrêt ait été demandé. Le dernier événement journalisé précède le redémarrage de moins d'une minute dans la quasi-totalité des cas.
C'est le profil d'une coupure d'alimentation, d'un reset matériel ou d'un gel total du noyau — Windows n'a pas eu le temps d'écrire quoi que ce soit.
Ces 30 événements sont répartis sur toute la période (octobre 2025 → juillet 2026), sans lien avec les vagues de BSOD. C'est la population la plus préoccupante pour une hypothèse matérielle, et c'est aussi celle sur laquelle les logs sont, par construction, muets.
Population B — 15 écrans bleus avec code d'erreur (33 %)
| Code | Nb | Nom | Signification |
|---|---|---|---|
0x0000009F |
10 | DRIVER_POWER_STATE_FAILURE | Un pilote bloque une requête de changement d'état d'alimentation (mise en veille, reprise, arrêt). Paramètre 1 = 0x3 dans les 10 cas : un objet de périphérique bloque une IRP trop longtemps. |
0x00000050 |
3 | PAGE_FAULT_IN_NONPAGED_AREA | Accès à une adresse mémoire invalide. Paramètre 2 = 0 → il s'agit d'une lecture (confirmé par WinDbg : AV.Type = Read). |
0x0000003B |
1 | SYSTEM_SERVICE_EXCEPTION | Exception 0xC0000005 (violation d'accès) en mode noyau. |
0x000000A0 |
1 | INTERNAL_POWER_ERROR | Erreur interne du gestionnaire d'alimentation. |
12 des 15 BSOD (80 %) sont des erreurs liées à une transition d'alimentation (0x9F + 0xA0). Aucun n'est précédé d'une demande d'arrêt propre → il s'agit de transitions veille S3 / reprise / démarrage rapide, pas d'un arrêt lancé depuis le menu Démarrer.
5. Chronologie — trois régimes successifs
| Période | Régime dominant |
|---|---|
| 29/10/2025 → 23/12/2025 | Uniquement des coupures sèches (2 événements) |
| 25/12/2025 → 29/03/2026 | Vague de 10 × 0x9F — DRIVER_POWER_STATE_FAILURE, souvent 2 le même jour, entremêlée de coupures sèches |
| 16/04/2026 → 19/05/2026 | 1 × 0xA0, 1 × 0x3B — puis les BSOD cessent |
| 19/05/2026 → 28/07/2026 | Retour aux seules coupures sèches (7 événements) |
| 31/07/2026 → 03/08/2026 | Nouvelle vague : 3 × 0x50 en 4 jours |
Les BSOD ne sont donc pas un phénomène continu : ce sont des vagues qui apparaissent et disparaissent, ce qui est le comportement typique d'une cause logicielle (installation ou mise à jour d'un pilote). Les coupures sèches, elles, sont présentes en continu du premier au dernier jour — comportement typique d'une cause matérielle.
6. Cause de la vague en cours : amdfendr.sys (AMD Crash Defender)
6.1 — La preuve : l'analyse du vidage mémoire
!analyze -v sur C:\Windows\Minidump\073126-9718-01.dmp (crash du 31/07/2026 08:54) donne la pile d'appels complète :
nt!KeBugCheckEx
nt!MiSystemFault
nt!MmAccessFault
nt!KiPageFault
nt!LZNT1FindMatchStandard+0xce <-- instruction fautive
nt!LZNT1CompressChunk+0xd7
nt!RtlCompressBufferLZNT1+0x80
nt!RtlCompressBuffer+0x6f
amdfendr+0x13e1b <-- L'APPELANT
MODULE_NAME: amdfendr
IMAGE_NAME: amdfendr.sys
FAILURE_BUCKET_ID: AV_amdfendr!unknown_function
AV.Type: Read
AV.Page.Virtual: 0xffff830288400000
Adresse fautive: 0xffff830288401000
Le mécanisme est limpide. amdfendr.sys appelle RtlCompressBuffer, la fonction de compression du noyau Windows, en lui passant un tampon dont la taille annoncée dépasse la taille réellement allouée. Le compresseur LZNT1 lit donc au-delà de la fin du tampon, tombe sur une page non mappée, et le noyau plante.
L'adresse fautive …88401000 est exactement à 0x1000 octets (une page mémoire) du début de la page valide …88400000. C'est la signature manuelle du dépassement de tampon : la lecture a franchi la frontière de page juste après la fin de la zone légitime.
Correction d'un point technique de la première version : le déplacement constant 0x3ae que j'avais relevé sur les trois écrans bleus se situe dans ntoskrnl (nt!LZNT1FindMatchStandard+0xce), pas dans amdfendr.sys. C'est pour cette raison qu'il est identique d'un crash à l'autre : c'est toujours la même fonction du noyau qui est mise en défaut. L'intuition — « le même chemin de code plante à chaque fois » — était juste ; son attribution à un pilote tiers ne l'était pas.
Notons enfin que l'horodatage réel du binaire est le 4 juin 2021 — encore plus ancien que sa date de fichier.
6.2 — Confirmation par les rapports WER
Après élévation de privilèges, les deux rapports d'erreur Windows du 31/07/2026 ont pu être lus. Ils contiennent le verdict de Microsoft :
EventType = BlueScreen
Response.BucketId = AV_amdfendr!unknown_function
Sig[0] Code = 50
Sig[3] Paramètre 3 = fffff8031db903ae / fffff805091903ae
Sig[4] Paramètre 4 = 2
AV_amdfendr!unknown_function : Access Violation imputée au module amdfendr.sys. Les deux rapports du 31/07, produits indépendamment, aboutissent au même classement — et au même que l'analyse du vidage ci-dessus. Trois déterminations convergentes.
6.3 — Ce qu'est ce pilote
| Fichier | Description | Version | Date |
|---|---|---|---|
amdfendr.sys |
AMD Crash Defender | 21.30.0.9 | 07/02/2022 |
amdfendrmgr.sys |
AMD Crash Defender Manager Driver | 21.30.0.9 | 07/02/2022 |
AMD Crash Defender est un composant des pilotes Radeon Adrenalin de la génération 21.30 / 22.x. Son rôle est d'intercepter les plantages du pilote graphique pour tenter de rétablir l'affichage sans redémarrer. Autrement dit : c'est le mécanisme censé éviter les écrans bleus qui les provoque.
Ce composant est connu pour être instable dans cette génération de pilotes. AMD l'a profondément remanié dans les versions ultérieures.
Le pilote graphique de cette machine date du 18/01/2022 (version 30.0.14023.3004) pour une Radeon RX 6500 XT — soit quatre ans et demi sans mise à jour, alors que la carte est toujours pleinement prise en charge par les pilotes Adrenalin actuels.
Le pilote graphique est également un candidat classique pour la famille 0x9F (DRIVER_POWER_STATE_FAILURE) : c'est typiquement lui qui bloque une transition de mise en veille ou de reprise. La vague de 10 × 0x9F de l'hiver 2025-2026 pourrait donc relever de la même origine — à confirmer par l'analyse des vidages.
6.4 — Anomalie secondaire : le pilote réseau VirtualBox
VBoxNetLwf — VirtualBox NDIS6 Bridged Networking Driver, version 7.2.14.174565
Le journal System contient 20 erreurs VBoxNetLwf (ID 12) : « Le pilote a détecté une erreur de pilote interne sur \Device\VBoxNetLwf ».
Toutes sont comprises entre le 24/07/2026 06:55 et le 03/08/2026 07:43 — soit exactement depuis l'installation d'Oracle VirtualBox 7.2.14 le 24/07/2026 (fichiers pilotes datés du 17/07/2026). Aucune avant.
Le rythme est de deux erreurs par jour — une le matin, une le soir :
| Date | Matin | Soir |
|---|---|---|
| 24/07 | 06:55 | 18:02 |
| 27/07 | 08:02 | 18:22 |
| 29/07 | 06:27 | 17:36 |
| 30/07 | 07:25 | 19:10 |
| 02/08 | 06:36 | 21:54 |
C'est-à-dire à chaque allumage et à chaque extinction — exactement le symptôme décrit par Julien.
Corrélation avec les 3 écrans bleus 0x50 :
Erreur VBoxNetLwf |
Écran bleu correspondant | Écart |
|---|---|---|
| 31/07/2026 06:27:21 | BugCheck 0x50 à 06:27:34 |
13 s |
| 31/07/2026 08:54:01 | BugCheck 0x50 à 08:54:14 |
13 s |
| 03/08/2026 07:43:26 | BugCheck 0x50 à 07:43:37 |
11 s |
Et le 28/07/2026 07:52:02, une erreur VBoxNetLwf coïncide à la seconde près avec une coupure sèche sans BSOD.
Verdict sur VBoxNetLwf : la corrélation temporelle est réelle, mais elle ne fait pas de lui la cause des écrans bleus. Les rapports WER placent le code fautif dans amdfendr.sys. L'explication cohérente est que les deux pilotes sont sollicités à la même seconde, lors de la même transition d'alimentation : VBoxNetLwf y journalise une erreur interne à chaque fois (20 fois), et amdfendr.sys y plante occasionnellement (3 fois).
VBoxNetLwf reste néanmoins un défaut logiciel réel à traiter : un filtre NDIS qui signale une erreur interne à chaque démarrage et à chaque extinction n'est pas un fonctionnement normal. Il a été désactivé (voir §10). Mais il faut être clair : ce n'est pas lui qui provoquait les écrans bleus.
Leçon de méthode : une corrélation temporelle à 12 secondes sur 3 événements, aussi frappante soit-elle, ne vaut pas une preuve. C'est la lecture du rapport WER — qui a nécessité une élévation de privilèges — qui a tranché. La constance du déplacement
0x3aeétait bien la bonne piste ; c'est son attribution àVBoxNetLwfqui était fausse.
6.5 — Deux attributions antérieures invalidées
RustDesk — le fichier CLAUDE.md attribuait les écrans bleus 0x50 du 31/07/2026 aux pilotes RustDesk (écran virtuel usbmmidd_v2, imprimante virtuelle), désactivés le jour même. Cette explication ne tient pas : un troisième 0x50 s'est produit le 03/08 avec la même signature, alors que usbmmidd_v2 était désactivé depuis trois jours. Le dossier C:\Program Files\RustDesk\drivers — qui ne contenait déjà plus qu'un RustDeskPrinterDriver.disabled — a été renommé en drivers.disabled par sécurité.
VirtualBox — voir ci-dessus. Suspect n°1 de la première version de cette page, disculpé par les rapports WER.
Ces deux erreurs ont la même origine : trois logiciels installés dans la même fenêtre de temps (VirtualBox le 24/07, RustDesk le 31/07) ont capté l'attention, alors que le vrai coupable était un pilote présent depuis longtemps et sans rapport avec ces installations.
7. Ce que les logs ne permettent PAS d'accuser
Il faut être clair sur ce point : à ce stade, aucune donnée ne désigne un composant électronique défectueux.
| Vérification | Résultat | Interprétation |
|---|---|---|
WHEA-Logger (erreurs machine remontées par le firmware : CPU, mémoire, bus PCIe, cache) |
0 événement sur 9 mois | Aucune erreur matérielle corrigible ou fatale détectée par le processeur. C'est un signal négatif fort contre une défaillance CPU ou mémoire franche. |
| État de santé des 5 disques | Tous Healthy / OK |
Aucune alerte |
| Erreurs disque / NTFS | 2 Ntfs 50 + 3 volmgr 161 en 90 jours |
Les volmgr 161 sont des conséquences des crashes (échec d'écriture du fichier de vidage), pas des causes |
Nuance importante sur WHEA : l'absence d'erreur WHEA ne disculpe pas le matériel pour la Population A. Une coupure d'alimentation brutale ou un gel total ne laisse par définition aucune trace, puisque le système n'a plus le temps d'écrire. WHEA ne couvre pas non plus les défaillances d'alimentation, de VRM ou de connectique.
SMART complet — relevé du 2026-08-03 via smartmontools 7.5
Windows n'exposait aucun compteur SMART sur ce chipset A320 (Get-StorageReliabilityCounter ne renvoie rien). smartctl a permis de lire directement les contrôleurs.
| Disque | Rôle | Santé | Heures | Cycles | Secteurs réalloués | Erreurs CRC | Temp. | Usure |
|---|---|---|---|---|---|---|---|---|
| Patriot Burst 240 Go (SSD) | Système (C:) | PASSED | 11 111 | 1 066 | 0 | 0 | 33 °C | SSD_Life_Left = 88 % — 15 To écrits |
| Toshiba HDWD110 1 To (P300 CMR) | Données (D:) | PASSED | 14 481 | 1 416 | 0 | 0 | 41 °C (max 49) | — |
| Seagate/Samsung ST1000LM024 1 To | Boîtier USB (E:) | PASSED | 60 187 | 5 800 | 0 | 0 | 39 °C (max 56) | — |
| Seagate ST8000AS0002 8 To (SMR) | Sauvegarde USB (F:) | PASSED | 19 823 | 2 166 | 0 | 0 | 46 °C (seuil 45 dépassé par le passé) | — |
Conclusion : aucun disque n'est défaillant. Zéro secteur réalloué, zéro secteur en attente, zéro erreur CRC, aucun journal d'erreurs SMART sur les quatre. Le SSD système conserve 88 % de sa durée de vie et n'a que 15 To d'écriture au compteur — il est hors de cause. L'hypothèse « SSD en fin de vie » est écartée.
Deux points annexes : le disque du boîtier USB affiche 60 187 heures, soit près de 7 ans d'allumage cumulé — sans le moindre défaut, mais il mérite une surveillance. Et le Seagate 8 To de sauvegarde a franchi son seuil de température de flux d'air (46 °C pour un seuil à 45 °C) : à surveiller, sans rapport avec les plantages.
⚠ Le compteur qui change la perspective
Unsafe_Shutdown_Count du SSD système : 146 arrêts brutaux pour 1 066 mises sous tension — soit 13,7 % des extinctions qui se sont mal passées.
Or le journal d'événements ne recense que 45 arrêts anormaux depuis octobre 2025. Une centaine d'arrêts brutaux sont donc antérieurs à la réinstallation de Windows du 28/10/2025.
C'est une information importante : le problème n'est ni récent, ni né de la réinstallation. Il est installé de longue date, et la réinstallation de Windows ne l'a pas réglé — ce qui affaiblit d'autant les hypothèses purement logicielles pour la Population A, et renforce la piste matérielle.
8. Facteurs aggravants identifiés dans la configuration
Démarrage rapide — était activé, ✅ désactivé le 2026-08-03
Le démarrage rapide (Fast Startup, HiberbootEnabled = 1) était actif jusqu'au 03/08/2026. Avec ce réglage, « Arrêter » n'éteint pas réellement Windows : le noyau et les pilotes sont mis en hibernation dans un fichier, puis rechargés tels quels au démarrage suivant.
Conséquences sur ce cas :
- C'est la première cause connue des écrans bleus
0x9F— qui représentent 10 des 15 BSOD relevés ici. - Cela explique qu'aucun crash ne soit précédé d'un arrêt propre dans les logs : les transitions concernées sont des hibernations/reprises, pas de vrais arrêts.
- Un état de pilote corrompu était réinjecté à chaque démarrage au lieu d'être réinitialisé — ce qui transforme un bug ponctuel en panne récurrente.
Depuis la désactivation, chaque arrêt réinitialise complètement l'état des pilotes. Effet de bord attendu : le démarrage est un peu plus lent — c'est normal et souhaitable ici.
Mémoire : une seule barrette, sous-cadencée
Un seul module de 16 Go occupant DIMM 0 (canal B) — donc pas de double canal, et la barrette tourne à 2400 MHz au lieu de 2666. Ce n'est pas une cause de panne en soi, mais c'est une configuration à connaître. Point positif pour le diagnostic : avec une seule barrette, un test mémoire est simple à interpréter et il n'y a pas de problème d'appairage possible.
BIOS de 2020
Version 1.40 datée du 08/12/2020, jamais mise à jour depuis. MSI a publié des révisions ultérieures pour l'A320M-A PRO, comportant des correctifs AGESA sur la gestion de l'alimentation et la compatibilité mémoire — directement pertinents pour des erreurs 0x9F et 0xA0.
Pilote graphique de 2022 — le facteur central
Pilote Radeon 30.0.14023.3004 du 18/01/2022 sur une RX 6500 XT, alors que la carte est toujours pleinement prise en charge par les Adrenalin actuels. C'est ce pilote qui embarque le amdfendr.sys fautif (binaire du 4 juin 2021). Plus qu'un facteur aggravant : c'est la cause identifiée des 0x50, et un suspect sérieux pour les 0x9F.
Espace disque système
71 Go libres sur 223 Go (C:) — suffisant, mais à surveiller : MEMORY.DMP occupe 2,4 Go, et sa copie de sauvegarde 2,31 Go de plus sur D:. Avec AlwaysKeepMemoryDump = 1 désormais actif, le vidage complet ne sera plus supprimé automatiquement par le nettoyage de disque — c'est voulu, mais cela demande de surveiller l'espace libre.
9. Diagnostic de synthèse
Il y a très probablement deux problèmes distincts, pas un seul.
Problème 1 — logiciel, identifié formellement.
amdfendr.sys (AMD Crash Defender, version 21.30.0.9 de février 2022) provoque les écrans bleus 0x50. Les rapports WER de Windows le désignent nommément, deux fois indépendamment (AV_amdfendr!unknown_function), et la signature d'adresse constante (0x3ae) confirme un défaut de code reproductible. Il est embarqué dans un pilote Radeon de janvier 2022, jamais mis à jour depuis. Le démarrage rapide amplifiait le phénomène. Ce même pilote est un candidat sérieux pour la vague de 0x9F de l'hiver. C'est traitable immédiatement et sans risque : il suffit d'installer un pilote AMD à jour.
Problème 2 — cause encore indéterminée, présent en continu depuis au moins octobre 2025.
30 coupures sèches réparties sur 9 mois, sans aucune trace exploitable. La vague de 10 × 0x9F de l'hiver 2025-2026 relève probablement aussi d'un pilote (autre que VirtualBox, installé bien plus tard), mais les coupures sèches restent inexpliquées. Les hypothèses ouvertes, par ordre de vraisemblance sur une machine de cet âge :
Le SMART apporte ici un élément décisif : avec 146 arrêts brutaux pour 1 066 démarrages, dont une centaine antérieurs à la réinstallation de Windows, le phénomène est ancien et a survécu à une remise à zéro complète du système. Hypothèses ouvertes, par ordre de vraisemblance :
- Alimentation vieillissante — condensateurs fatigués, tension instable sous charge. C'est l'hypothèse n°1 pour des coupures nettes sans trace, c'est le composant le plus âgé et le plus sollicité, et c'est cohérent avec un problème qui traverse les réinstallations de Windows.
- Thermique — pâte thermique sèche après 6-7 ans, ventilateur de CPU encrassé, coupure de protection.
- Connectique / oxydation — barrette mémoire, connecteurs d'alimentation, câbles SATA.
- Mémoire — moins probable (aucune erreur WHEA), mais non écartée tant qu'un test complet n'a pas été passé.
SSD système— écarté : SMART impeccable, 88 % de durée de vie restante, aucune erreur.
10. Actions recommandées, par ordre de priorité
✅ Déjà appliqué le 2026-08-03 à 08h29
| # | Action | Résultat |
|---|---|---|
| 1 | Filtre VirtualBox NDIS6 Bridged Networking désactivé sur les cartes Ethernet et Ethernet 2 |
✅ Enabled = False sur les deux |
| 2 | Démarrage rapide désactivé (HiberbootEnabled : 1 → 0) |
✅ |
| 3 | Mini-vidages portés à 50 (MinidumpsCount : 5 → 50) et AlwaysKeepMemoryDump = 1 |
✅ Le vidage complet ne sera plus supprimé par le nettoyage de disque |
| 4 | C:\Program Files\RustDesk\drivers renommé en drivers.disabled |
✅ (ne contenait déjà plus qu'un RustDeskPrinterDriver.disabled) |
| 5 | MEMORY.DMP du crash du 03/08 sauvegardé → D:\MEMORY_20260803_0743_bugcheck50.DMP (2,31 Go) |
✅ La preuve est préservée du prochain écrasement |
Priorité 1 — l'action décisive
| # | Action | Objectif |
|---|---|---|
| 6 | Réinstaller proprement le pilote AMD Radeon. Télécharger l'Adrenalin actuel pour RX 6500 XT sur le site AMD, désinstaller l'ancien avec DDU (Display Driver Uninstaller) en mode sans échec, puis installer le nouveau. Choisir une installation minimale/personnalisée, sans les composants optionnels. | Traite la cause identifiée. Remplace amdfendr.sys 21.30.0.9 (2022) par une version où AMD Crash Defender a été remanié. Susceptible de régler à la fois les 0x50 et les 0x9F. |
Pourquoi DDU et pas une simple mise à jour : l'installateur AMD ne remplace pas systématiquement les pilotes de la génération 21.30 et peut laisser
amdfendr.sysen place. DDU garantit une table rase.
Priorité 2 — confirmer et combler les angles morts
| # | Action | Objectif |
|---|---|---|
| ✅ Fait le 03/08 à 09h00 — voir §6.1. Verdict confirmé et mécanisme établi | ||
| ✅ Fait le 03/08 à 09h00 — voir §7. Aucun disque défaillant | ||
| 9 | Test mémoire complet : MemTest86 sur clé USB, au moins 4 passes complètes, de préférence une nuit entière. L'outil intégré à Windows est insuffisant. | Écarte ou confirme la RAM de façon définitive. Simple ici : une seule barrette. |
| 10 | Mettre à jour le BIOS MSI A320M-A PRO (actuel : 1.40 de 2020). | Correctifs AGESA sur la gestion d'alimentation, directement liés aux 0x9F/0xA0 |
Priorité 3 — intervention physique, pour la Population A
À n'engager qu'après avoir traité le pilote AMD et laissé passer deux ou trois semaines de relevés : si les coupures sèches s'arrêtent aussi, cette section devient inutile.
| # | Action | Objectif |
|---|---|---|
| 11 | Relever les références de l'alimentation (marque, modèle, wattage, année). | Information manquante et déterminante |
| 12 | Dépoussiérer : ventilateur et radiateur CPU, ventilateur de la carte graphique, ventilateurs de boîtier, filtres, bloc d'alimentation. | Cause thermique |
| 13 | Réextraire et réinsérer la barrette mémoire et les connecteurs d'alimentation ATX 24 broches et EPS 8 broches. Nettoyer les contacts. | Cause connectique / oxydation |
| 14 | Refaire la pâte thermique du processeur si elle n'a pas été changée depuis l'assemblage. | Cause thermique |
| 15 | Surveiller les températures et les tensions en fonctionnement (HWiNFO64), en particulier les rails 12 V, 5 V et 3,3 V sous charge. | Détecte une alimentation qui décroche |
| 16 | Si les coupures sèches persistent après tout ce qui précède : tester avec une autre alimentation. | Test décisif de l'hypothèse n°1. À noter : la RX 6500 XT est peu gourmande (~107 W), mais une alimentation fatiguée décroche sur les pics de la carte graphique |
11. Limites de cette analyse
À mentionner pour que les conclusions soient lues à leur juste valeur :
- Le journal d'événements ne remonte qu'au 29/10/2025 (réinstallation de Windows la veille). Le compteur SMART
Unsafe_Shutdown_Count(146) permet toutefois d'affirmer que le phénomène est bien antérieur — mais sans en connaître ni la chronologie ni la nature. - Un seul vidage a pu être analysé (31/07 08:54). Il concerne un
0x50. Aucun vidage exploitable n'existe pour les 10 écrans bleus0x9Fde l'hiver — leur attribution àamdfendrreste une hypothèse plausible, pas un fait établi. - Aucune donnée de température ni de tension en fonctionnement n'est disponible sans capteur logiciel dédié (HWiNFO64). Les températures SMART relevées sont celles des disques, pas du processeur ni de la carte graphique.
- Le déclencheur reste inconnu : on sait comment
amdfendrplante (dépassement de tampon surRtlCompressBuffer), pas pourquoi cela n'arrive que 3 fois sur des dizaines de transitions. - Trois des quatre mini-vidages présents font 0 octet (
080326-9906-01.dmpdu 03/08, deux du 31/07) — cohérent avec les erreursvolmgr 161: Windows n'a pas réussi à écrire le vidage. Seul073126-9718-01.dmp(31/07 08:54, 1,1 Mo) est exploitable. Cette difficulté récurrente à écrire un vidage est en soi un signal : elle peut trahir un problème d'accès au disque système au moment du crash. - La cause des 30 coupures sèches reste entièrement ouverte. Rien dans les logs ne permet de la désigner, par construction.
12. Journal des relevés
Un relevé toutes les 1 à 2 semaines suffit à mesurer l'effet des actions engagées. Le script ajoute automatiquement une ligne à ce tableau :
powershell -ExecutionPolicy Bypass -File "D:\Syncthing\Jux_univers\Jux-scripts\PC-Health\collect_bsod.ps1"
À lancer en administrateur pour que les compteurs SMART soient lus ; sinon la ligne est écrite sans eux. L'option -DryRun affiche le résultat sans rien écrire dans BookStack. Le script relève les arrêts anormaux, les codes bugcheck, les erreurs VBoxNetLwf, les erreurs WHEA, la version du pilote AMD (pour dater sa réinstallation), et signale tant que amdfendr 21.30 est en place.
La colonne « Actions faites depuis » est à compléter à la main.
| Date du relevé | Arrêts anormaux depuis le dernier relevé | dont BSOD | Codes rencontrés | Erreurs VBoxNetLwf |
WHEA | Actions faites depuis | Observations |
|---|---|---|---|---|---|---|---|
| 2026-08-03 | 45 (cumul 9 mois) | 15 | 10×9F, 3×50, 1×3B, 1×A0 |
20 | 0 | — (état initial) | Analyse initiale. Deux populations distinctes. Cause des 0x50 établie par analyse du vidage : amdfendr.sys déborde un tampon sur RtlCompressBuffer. Actions 1 à 5 + 7 + 8 faites. SMART : 4 disques sains, mais 146 arrêts brutaux au compteur du SSD → problème antérieur à la réinstallation. |
Référence — état au 2026-08-03 : SSD système 11 111 h / 1 066 cycles / 146 arrêts brutaux / 88 % de vie restante. Comparer Unsafe_Shutdown_Count d'un relevé à l'autre donne un compteur de coupures indépendant du journal Windows :
& 'C:\Program Files\smartmontools\bin\smartctl.exe' -A /dev/pd0
13. Indicateur de succès
Le suivi doit permettre de trancher entre les deux problèmes :
- Si les écrans bleus cessent après la réinstallation du pilote AMD mais que les coupures sèches continuent → le problème logiciel est réglé, le problème matériel est confirmé et isolé. On passe à la priorité 3.
- Si tout cesse → la cause était entièrement logicielle, et l'hypothèse du composant défectueux tombe. Un pilote graphique instable peut en effet provoquer aussi bien des écrans bleus que des gels totaux sans trace.
- Si les écrans bleus persistent malgré un pilote AMD à jour → analyser le nouveau vidage sous WinDbg (les mini-vidages sont maintenant conservés, 50 au lieu de 5), et l'hypothèse d'une carte graphique défaillante — et non plus seulement de son pilote — devient sérieuse.
Point de vigilance sur la carte graphique : c'est le composant qui concentre désormais le plus de signaux. Si des artefacts visuels, des écrans noirs momentanés ou des gels pendant un jeu ou une vidéo apparaissent, il faut le noter dans le journal — ce serait l'indice d'un défaut matériel de la RX 6500 XT.
Deuxième indicateur, indépendant du journal Windows : l'écart de Unsafe_Shutdown_Count entre deux relevés. Il compte les coupures réelles même quand Windows n'a rien pu journaliser — donc il capte la Population A, celle qui est invisible autrement. C'est le chiffre à surveiller pour trancher la question matérielle.
14. Fichiers et emplacements
| Quoi | Où |
|---|---|
| Script de relevé | D:\Syncthing\Jux_univers\Jux-scripts\PC-Health\collect_bsod.ps1 (Syncthing, disponible sur toutes les machines) |
| Vidage du crash du 03/08, sauvegardé | D:\MEMORY_20260803_0743_bugcheck50.DMP (2,31 Go) |
| Mini-vidage exploitable du 31/07 | C:\Windows\Minidump\073126-9718-01.dmp (1,1 Mo) — accès administrateur |
| Vidages suivants | C:\Windows\Minidump\ — 50 conservés désormais (au lieu de 5) |
smartctl |
C:\Program Files\smartmontools\bin\smartctl.exe |
| Débogueur console | cdbX64.exe (dans le PATH via %LOCALAPPDATA%\Microsoft\WindowsApps) |
| Contexte projet | CLAUDE.md du dépôt Claude-pcelio+jux, section « Stabilité du PC Windows eliob » |
Page tenue à jour par Claude Code. Analyse initiale et investigation complète le 2026-08-03.