Homelab — infrastructure auto-hébergée
2026 En coursLe principe
Reprendre la main sur son infrastructure. Plutôt que de louer des services à des tiers, faire tourner ses propres applications sur son propre matériel, chez soi, avec un contrôle total sur les données et sur la manière dont elles circulent.
Le support est un Raspberry Pi 5 (8 Go de RAM, SoC ARM Cortex-A76 quadricœur), une carte de la taille d’une carte bancaire consommant une dizaine de watts en fonctionnement. La contrainte est réelle — pas de redondance matérielle, une bande passante résidentielle — mais elle impose une rigueur d’architecture qu’un serveur surdimensionné n’exige jamais. Chaque service doit justifier son empreinte mémoire, chaque écriture disque doit être pesée.
Le socle système
Le système d’exploitation est Raspberry Pi OS Lite 64 bits, une Debian allégée sans environnement graphique : moins de RAM consommée, moins de processus en arrière-plan, et surtout une surface d’attaque réduite. Un serveur n’a pas besoin d’un bureau.
L’accès se fait exclusivement en SSH par authentification à clé publique (Ed25519), l’authentification par mot de passe étant désactivée au niveau du démon sshd. Trois couches complètent le durcissement de base :
- UFW en pare-feu applicatif, avec une politique de refus par défaut
- fail2ban, qui analyse les journaux d’authentification et bannit dynamiquement les adresses à l’origine de tentatives répétées
- unattended-upgrades, qui applique les correctifs de sécurité Debian sans intervention
Le poste de travail est sous Windows, relié au serveur via l’extension Remote-SSH de VS Code : les fichiers du Pi sont édités comme s’ils étaient locaux, avec coloration syntaxique et terminal intégré. Une nuance importante sur le pare-feu, apprise en route : Docker écrit ses propres règles iptables en amont de celles d’UFW, ce qui signifie qu’un port publié par un conteneur reste joignable même si UFW ne l’autorise pas. La conséquence est architecturale — aucun service d’administration ne publie de port, tout passe par le réseau interne Docker.
La conteneurisation comme brique de base
Chaque application tourne dans son propre conteneur Docker, décrit par un fichier docker-compose.yml versionné. Cette isolation permet d’ajouter, mettre à jour ou supprimer un service sans jamais affecter les autres : pas de conflit de dépendances, pas d’effet de bord, pas de bibliothèque système partagée qu’une mise à jour viendrait casser.
Les conteneurs communiquent entre eux via un réseau Docker bridge dédié (proxy), en s’adressant par leur nom de service plutôt que par une adresse IP. Le reverse proxy joint Grafana sur grafana:3000 sans qu’aucun port ne soit exposé à l’hôte, et a fortiori à Internet.
L’ensemble de la configuration vit dans un dépôt Git — une approche proche de l’infrastructure as code. Le dépôt contient la structure : fichiers Compose, configurations de services, scripts. Il exclut délibérément les données persistantes et les secrets, isolés dans des fichiers .env référencés par variables d’environnement. La conséquence pratique est appréciable : en cas de défaillance matérielle, l’intégralité de l’infrastructure se reconstruit à partir d’un git clone et d’une poignée de commandes.
Portainer complète le dispositif comme interface d’observation — logs, métriques temps réel, inspection des volumes et des réseaux. Volontairement en lecture seule sur le socket Docker : l’accès à ce socket équivaut à un accès root sur la machine, et il n’y a aucune raison d’ouvrir cette porte pour un outil qui sert essentiellement à regarder.
Exposition et chiffrement
Le point d’entrée unique est Caddy, un reverse proxy qui gère nativement l’obtention et le renouvellement des certificats TLS via le protocole ACME auprès de Let’s Encrypt. Chaque service se déclare en trois lignes de configuration, et le HTTPS est actif sans qu’aucun certificat n’ait à être manipulé manuellement.
En amont, la zone DNS a été migrée vers Cloudflare : propagation en quelques secondes, gestion fine des enregistrements, et surtout accès à une API qui permettra à terme la validation ACME par challenge DNS — indispensable pour obtenir des certificats sur des services qui ne sont pas exposés publiquement, ou pour des certificats wildcard.
Côté réseau, la connexion fibre dispose d’une IPv4 full-stack, non partagée et non soumise au CGNAT, condition sine qua non pour héberger sur les ports 80 et 443. Deux règles de redirection NAT sur le routeur acheminent le trafic vers le Pi.
Le principe directeur : exposer le strict minimum. Seuls les sites web publics sont accessibles depuis Internet. Tout ce qui relève de l’administration — supervision, gestion des conteneurs, futurs services de stockage — reste confiné au réseau local et sera joignable à distance exclusivement via VPN.
Supervision
La chaîne d’observabilité repose sur la pile Prometheus.
node-exporter expose les métriques de l’hôte au format Prometheus : utilisation processeur par mode, mémoire, systèmes de fichiers, interfaces réseau, capteurs thermiques. cAdvisor fait de même à l’échelle des conteneurs, en lisant les cgroups v2 du noyau. Prometheus interroge ces deux collecteurs à intervalle régulier et stocke les séries temporelles dans sa base TSDB. Grafana interroge Prometheus en PromQL et restitue le tout sous forme de tableaux de bord.
Deux paramètres ont été ajustés pour ménager le support de stockage : l’intervalle de collecte porté à 30 secondes, et la rétention limitée à 15 jours. Une base de séries temporelles écrit en permanence, et une carte SD supporte un nombre fini de cycles d’écriture.
L’affichage physique
Un écran TFT 480×320 est monté directement sur le connecteur GPIO du Pi et piloté en SPI. Sa mise en service a demandé de comprendre la chaîne graphique du noyau Linux : activation du bus SPI, chargement d’un overlay device tree (piscreen, pilotant un contrôleur ILI9486), et vérification de la création du framebuffer par le pilote fbtft. Le résultat est un périphérique /dev/fb0 en 480×320 à 31 images par seconde.
Plutôt que d’installer un serveur graphique et un navigateur en mode kiosque — lourd, lent et inadapté à cette résolution — l’affichage est produit par un script Python qui compose une image avec Pillow et l’écrit directement dans le framebuffer. La conversion depuis RGB888 vers le format RGB565 little-endian attendu par le matériel est vectorisée avec NumPy, ce qui divise le coût CPU par rapport à une boucle Python naïve sur 153 600 pixels.
Le tableau de bord affiche température du SoC, charge processeur et load average, mémoire, espace disque, débit réseau, uptime et nombre de conteneurs actifs. Il lit les valeurs directement dans /proc et /sys plutôt que d’interroger Prometheus — l’écran continue donc de fonctionner même si la pile de supervision est arrêtée.
Deux raffinements méritent d’être notés. Le script interroge le registre vcgencmd get_throttled, qui indique non seulement si le processeur est actuellement bridé thermiquement ou en sous-tension, mais aussi si l’un de ces événements s’est produit depuis le démarrage. C’est un diagnostic précieux : une alimentation insuffisante provoque des plantages erratiques et de la corruption de données, et sans cet indicateur le symptôme reste inexplicable. En cas de dépassement de seuil, l’affichage bascule en mode alerte et ralentit son rafraîchissement — quand la machine souffre, ce n’est pas le moment de lui demander davantage.
Le tout est encapsulé dans une unité systemd avec redémarrage automatique et priorité nice abaissée, garantissant que l’affichage ne prendra jamais le pas sur les services applicatifs.
Sauvegardes
Un script tar archive quotidiennement les volumes de données, déclenché par cron, avec rotation automatique au-delà de quinze jours. La distinction entre les deux mécanismes est structurante : Git versionne la configuration, l’archive protège les données. Les deux sont nécessaires et aucun ne remplace l’autre.
La limite actuelle est assumée et documentée : cette sauvegarde réside sur le même support physique que les données. Elle protège d’une erreur de manipulation, pas d’une défaillance matérielle. La correction est planifiée avec la migration vers un stockage externe.
Déploiement continu
Le portfolio lui-même — un site statique Astro avec Tailwind — est déployé selon un modèle inspiré du GitOps :
Poste de travail → git push → GitHub → Pi (polling) → build → production
Le serveur interroge périodiquement la branche main, compare les SHA de commit, et déclenche un git reset --hard suivi d’un npm ci && npm run build dès qu’une divergence apparaît. Caddy sert le répertoire dist/ généré.
Le point important est la direction du flux : le dépôt distant est l’unique source de vérité, et le serveur n’est jamais modifié directement. Toute altération locale est écrasée au déploiement suivant. Cette discipline évite la dérive de configuration, ce moment où l’état réel d’un serveur ne correspond plus à ce que la documentation décrit et où plus personne ne sait comment le reconstruire.
Feuille de route
Court terme
- VPN WireGuard. Un tunnel chiffré moderne, reposant sur une cryptographie récente (ChaCha20, Curve25519, BLAKE2s) et implémenté dans l’espace noyau, ce qui lui donne des performances sans commune mesure avec les solutions antérieures. L’objectif est de rendre l’ensemble des services d’administration accessibles depuis n’importe où sans exposer un seul port supplémentaire sur Internet.
- Gitea. Une forge Git auto-hébergée, légère, qui accueillera les dépôts d’infrastructure et de projets. L’intérêt dépasse le simple hébergement de code : Gitea intègre un système d’actions compatible avec la syntaxe GitHub Actions, ce qui ouvre la voie à une intégration continue entièrement locale.
- Hébergement multi-sites. L’architecture est conçue pour accueillir plusieurs domaines distincts sur la même machine, Caddy assurant le routage par nom d’hôte (SNI) et la gestion indépendante des certificats. Chaque site disposera de son propre pipeline de déploiement.
- Webhooks de déploiement. Remplacer le polling par une notification poussée depuis le dépôt distant, avec vérification de signature HMAC et sérialisation des déploiements concurrents. Le gain n’est pas seulement la latence, mais la suppression de requêtes inutiles.
Moyen terme
- Migration vers un stockage SSD. Une carte SD supporte mal les écritures soutenues d’une base de données ou d’un moteur de séries temporelles. Le passage à un SSD — en USB 3.0, ou en NVMe via le connecteur PCIe du Pi 5 — apportera à la fois de la fiabilité et un gain de débit significatif. Ce changement conditionne l’arrivée des services de stockage.
- Nextcloud et Immich. Deux services lourds en données : une suite de synchronisation de fichiers, et une bibliothèque photo avec sauvegarde automatique depuis mobile et reconnaissance visuelle exécutée localement. L’objectif est de remplacer des services cloud commerciaux par des équivalents auto-hébergés, sans quota et sans que les données quittent le domicile.
- Automatisations. Des services Python conteneurisés pour la collecte de données, la surveillance de valeurs et l’émission d’alertes, pilotés par un bot Discord servant d’interface de contrôle à distance depuis mobile.
- Alerting. Compléter la supervision par Alertmanager, afin de passer d’un modèle passif — consulter un tableau de bord — à un modèle actif : être notifié lorsqu’un seuil est franchi ou qu’un service cesse de répondre.
Réflexions ouvertes
Sauvegarde hors site. Une sauvegarde locale ne protège ni du vol, ni de l’incendie, ni d’un dégât des eaux. Une réplication chiffrée vers un stockage objet distant, avec déduplication et chiffrement côté client, est la suite logique.
Limites de l’hébergement résidentiel. Un serveur domestique dépend d’une alimentation électrique, d’une connexion grand public et d’un unique support de stockage. Pour du développement, de la démonstration et des projets personnels, c’est parfaitement adapté et extrêmement formateur. Pour de la production avec engagement de disponibilité, une architecture hybride s’impose : le homelab comme environnement de développement et de préproduction, un hébergement professionnel pour ce qui doit tenir un SLA. Savoir où placer cette frontière fait partie de l’apprentissage.
Reproductibilité complète. L’étape suivante en maturité serait de décrire la configuration système elle-même — pas seulement les conteneurs — sous forme déclarative, avec Ansible ou une distribution immuable. L’objectif : passer d’un serveur reconstructible en une heure à un serveur reconstructible en une commande.
Ce que le projet enseigne
Ce n’est pas un projet qu’on termine. C’est une infrastructure qui vit, qui tombe parfois, qu’il faut diagnostiquer et réparer.
La valeur réelle tient moins à la liste des services déployés qu’à la compréhension de ce qui se passe entre le moment où une requête quitte un navigateur et celui où une réponse s’affiche : résolution DNS, traversée du NAT, terminaison TLS, routage applicatif, isolation par namespaces. Chaque couche a été montée à la main, ce qui signifie que chaque couche peut être débogée.
Et la contrainte matérielle, loin d’être un handicap, se révèle pédagogique : sur une machine à 8 Go de RAM et une carte SD, on ne peut pas se permettre l’approximation.