/images/avatar.png

Ce site tourne sur un NUC Intel hébergé à la maison, derrière une connexion fibre standard. Il sert avant tout de terrain d’expérimentation pour tester des configurations serveur, des scripts d’automatisation, et des outils de sécurité open source.

Pas un site professionnel — un homelab : on casse des choses, on les répare, on apprend.

🌟 À ne pas manquer

Trois articles qui résument l’esprit du homelab :

📚 La documentation complète est dans Documentation et les scripts d’automatisation dans Scripts.

🛠️ Stack technique

OutilRôle
OpenRestyReverse proxy · nginx + LuaJIT · TLS 1.3
🔒 CrowdSecIDS/IPS communautaire collaboratif
🧱 CrowdSec AppSecWAF inline · OWASP CRS 4.x
☁️ CloudflareCDN · WAF · DNS · DDoS
🌐 HugoGénérateur de site statique
🤖 MCP Hugo ServerServeur MCP pour piloter ce site depuis une IA
📊 BetterStackMonitoring · Alertes · Logs

🐛 Vous avez trouvé une faille ?

Si vous découvrez un bug, une mauvaise configuration ou une faille de sécurité sur ce serveur, merci de me le signaler. Ce homelab est public et j’apprends de mes erreurs.

📨 Signalement responsable : www.arleo.eu/security.txt

Les signalements sont remerciés publiquement dans le Hall of Fame, ou restent anonymes sur demande.

Toute contribution à l’amélioration de la sécurité est la bienvenue.

Migration en cours
Le site migre progressivement de Grav CMS vers Hugo. Les anciennes URLs sont préservées, mais le rendu visuel évolue. Si vous voyez un bug, signalez-le.

Post-mortem : 3 timeouts MCP entre Cloudflare, NFS et OAuth

Ce qui s'est passé
  • Date : 9 mai 2026
  • Sévérité : P2
  • Statut : Résolu
  • Impact : create_page/update_page en timeout intermittent (~1 appel sur 3), causé par 3 bugs indépendants — expiration OAuth, IPAddressDeny bloquant l’appel Cloudflare, latence NFS QNAP pendant le backup

En bref

J’ai mis en production un Hugo MCP Server (FastAPI, 7 tools) qui me permet d’éditer arleo.eu depuis Claude.ai. Architecture : claude.ai → mcp-oauth-proxy NUC → hugo-mcp-proxy NUC → MCP server VM.

MCP et Git : séparer contenu et structure

En bref

Tu as un site Hugo. Tu veux pouvoir :

  1. Éditer le contenu via Claude.ai (publier un article, corriger une coquille, mettre à jour un draft) sans toucher à un terminal SSH.
  2. Versionner la structure (layouts, themes, hugo.toml, scripts de déploiement) dans Git, comme un dev sérieux.

Premier réflexe : « tout dans Git ». Les articles aussi. Le MCP commit, push, le webhook GitHub fait un rebuild. Propre, dans la philosophie GitOps.

Sauf que ça ne marche pas si bien. Voici pourquoi, et la solution simple que j’appelle la Stratégie 4.

Pourquoi « tout dans Git » casse en pratique

Imaginons que ton MCP fait un git commit à chaque create_page. Stratégie naïve, mais souvent proposée. Voici les problèmes :

Problème 1 — Conflit MCP ↔ Git

Tu push depuis ton laptop un nouveau layout (layouts/index.html modifié). Au même moment, le MCP est en train de commiter une nouvelle version d’un article. Race condition, le MCP peut faire un git pull --rebase qui échoue, ou pire, écraser ton commit local.

Problème 2 — Identité Git du MCP

Le MCP commit en tant que qui ? Avec quelle clé GPG ? Si tu as une politique « commits signés obligatoires », le MCP doit gérer une clé GPG, qu’il faut sécuriser, faire tourner, etc.

Problème 3 — Auto-commit indésirable

Tu fais un test, tu crées un article draft pour expérimenter, tu le supprimes. Mais le MCP a déjà commité. Maintenant tu as un commit “wip test” dans l’historique, à rebaser ou squasher manuellement.

Problème 4 — Réversibilité asymétrique

Un git revert côté repo n’a aucun effet sur les fichiers que le MCP a déjà créés. Tu te retrouves avec un repo et un état filesystem désynchronisés.

La Stratégie 4 : séparer les zones

L’idée : MCP et Git n’écrivent jamais sur les mêmes fichiers.

ZoneQui éditeVersionné dans Git ?
content/**/*.mdMCP exclusivement❌ NON (.gitignore)
layouts/, themes/, static/, hugo.toml, deploy.shGit push exclusivement✅ OUI

Le .gitignore côté repo :

content/
public/
resources/

Implications :

  • Le MCP peut écrire dans content/ quand il veut. Aucun conflit Git possible.
  • Tu peux faire git reset --hard côté repo en confiance — content/ reste intact.
  • Pas besoin que le MCP gère une identité Git.
  • Pas de “commit pollution”.

Trade-off : pas de versioning du contenu

Tu perds le versioning Git du contenu. C’est une perte réelle :

  • Pas de git blame sur un article pour voir qui a écrit quoi.
  • Pas de git log content/csp-nonce/index.fr.md pour voir l’historique.
  • Pas de PR review pour les articles.

Mitigation : snapshots VM + backup content/ chiffré quotidien sur QNAP. Ça couvre la récupération en cas de désastre, mais pas le versioning fin (qui-a-changé-quoi-quand).

Pour mon homelab perso (un seul auteur, articles techniques, pas de workflow de validation éditoriale), c’est un trade-off acceptable. Pour un blog d’équipe avec 10 contributeurs, je reconsidérerais.

Architecture finale

Hardening systemd : passer un service Python de 9.6 à 1.7

En bref

systemd-analyze security est un outil sous-utilisé. Il scanne tes unit files et calcule un score d’exposition de 0.0 (UNSAFE) à 10.0 (PERFECT). Les services Python custom sortent souvent autour de 9.6 par défaut — c’est mauvais.

J’ai fait passer mon service hugo-mcp (FastAPI exposant 7 tools MCP) de 9.6 → 1.7 sans casser la moindre fonctionnalité. Voici les directives qui comptent vraiment, et celles qui sont des pièges.

Le score initial

$ sudo systemd-analyze security hugo-mcp
→ Overall exposure level for hugo-mcp.service: 9.6 UNSAFE 😨

9.6 sur 10. Le service tourne en root équivalent, peut faire setuid(), peut allouer de la mémoire RWX, voit tous les processus du système, peut écrire partout, peut faire des syscalls arbitraires.

Pour un MCP qui édite du contenu Markdown et déclenche un build Hugo, c’est démesuré.

Migration Grav → Hugo : 32 fichiers, 0 régression

En bref

arleo.eu tournait sur Grav CMS depuis ~3 ans : flat-file, PHP-FPM, ModSecurity, Cloudflare. Tout marchait. Mais la dette opérationnelle s’accumulait : MAJ PHP, plugins Grav à patcher, TTFB qui grimpait à >800ms sur certaines pages.

J’ai migré vers Hugo (générateur de site statique en Go) en deux semaines, en gardant les mêmes URLs, le même contenu, et les deux langues FR/EN. Zéro régression côté SEO, indexation Cloudflare, ou liens internes. Voici comment.

Pourquoi Hugo

J’avais 3 critères :

  1. Performance — Statique pur. Pas de PHP, pas de DB. nginx sert directement les .html pré-générés.
  2. Sécurité — Surface d’attaque divisée par 10. Plus de PHP-FPM, plus d’exécution serveur sur les pages publiques.
  3. Multilingue propre — Hugo supporte nativement i18n via la convention index.{lang}.md (page bundles).

Hugo coche tout. Les alternatives évaluées : Eleventy (JS, mais moins mature niveau i18n), Zola (Rust, super, mais écosystème thèmes plus restreint), Gatsby (trop lourd pour un homelab).

Hugo MCP Server : connecter Claude.ai à Hugo

En bref

Connecter Claude.ai à un site Hugo hébergé dans une VM KVM en 30 minutes : un serveur FastAPI expose 6 outils MCP (lire, créer, modifier, supprimer des pages, rebuilder le site) via JSON-RPC 2.0, un proxy OAuth réutilise l’infrastructure existante, et chaque modification déclenche automatiquement un rebuild Hugo + une purge du cache Cloudflare.

Le code est disponible sur GitHub :

🧠 Pourquoi

Le protocole MCP (Model Context Protocol) d’Anthropic permet à Claude.ai de se connecter à des sources de données externes via des outils standardisés. Contrairement à Grav CMS qui est dynamique (PHP), Hugo génère du HTML statique — ce qui rend la gestion de contenu via MCP encore plus puissante : chaque modification est compilée et déployée instantanément.

VM Media KVM : isoler Sonarr, Radarr et SABnzbd

En bref

Migrer son media stack (Sonarr, Radarr, SABnzbd) dans une VM KVM dédiée sur Ubuntu 24.04 : isolation sécurité, snapshots facilités, NFS QNAP monté dans la VM, reverse proxy nginx sur l’hôte. La migration conserve intégralement les bases de données SQLite et la configuration existante.

Stack cible :

  • Hôte : NUC8i3BEH, Ubuntu Server, nginx reverse proxy, Plex (transcodage GPU)
  • VM media-vm : Ubuntu 24.04, 2 vCPU, 8 Go RAM, 120 Go (X5 NVMe), NFS QNAP
  • Services migrés : Sonarr (port 8989), Radarr (port 7878), SABnzbd (port 6789)

Pourquoi isoler le media stack dans une VM

Sonarr, Radarr et SABnzbd présentent une surface d’attaque non négligeable : accès réseau vers des indexeurs externes, exécution de scripts post-download, accès au système de fichiers de la bibliothèque. Les confiner dans une VM apporte :

Hugo