Choix Techniques
Choix techniques
Cette page explique pourquoi l'infrastructure est construite ainsi. Le « comment » est dans les pages de chaque service. Pour chaque choix, on trouve ce qui a été décidé, la raison, ce qui a été écarté et les limites acceptées.
Un choix qui n'a plus de raison d'être doit être revu, pas conservé par habitude.
Contraintes de départ
Ces contraintes ne sont pas des choix, mais elles en expliquent plusieurs.
- Box opérateur sans hairpin NAT : depuis le réseau local, le domaine public ne ramène pas vers le serveur.
- IP publique dynamique : il faut un DNS dynamique.
- Raspberry Pi en Wi-Fi uniquement : pas de câble possible jusqu'à lui. Débit faible et lien instable sur les gros transferts.
- Matériel domestique : deux machines, pas de redondance.
Architecture
Deux machines, deux rôles
Choix : le serveur principal porte tout ce qui est exposé à Internet. Le Raspberry Pi reste sur le réseau local.
Pourquoi : le dépôt de sauvegarde et le DNS local ne doivent pas tomber avec le serveur exposé. Si le serveur est compromis ou détruit, les sauvegardes sont ailleurs.
Limites : l'accès distant au Pi passe par le serveur principal (Sshwifty, ou Jellyfin derrière le reverse proxy). Si le serveur est en panne, le Pi n'est plus joignable de l'extérieur.
Tout en conteneurs, piloté par Portainer
Choix : les services tournent sous Docker, déployés en stacks Portainer. Un seul Portainer, sur le serveur principal, pilote les deux machines ; le Pi a un agent.
Pourquoi : une interface unique pour les deux machines, et des stacks qui se relisent et se redéploient. Portainer en version LTS pour limiter les changements de comportement.
Limites : quelques conteneurs viennent des modèles d'applications de Portainer et ne sont pas des stacks. Ils sont signalés dans leur page ; leur configuration n'est pas versionnée comme celle d'une stack.
Exposition et sécurité
SWAG comme reverse proxy
Choix : SWAG (nginx de LinuxServer.io).
Pourquoi : il regroupe nginx, le certificat Let's Encrypt wildcard par validation DNS et des modules prêts à l'emploi (bouncer CrowdSec, tableau de bord). Un certificat wildcard évite de publier chaque sous-domaine dans les journaux de transparence des certificats.
Limites : SWAG est exclu des mises à jour automatiques ; chaque mise à jour se fait à la main après lecture des notes de version.
Authelia devant les services
Choix : Authelia en authentification commune, avec second facteur.
Pourquoi : les services qui n'ont pas de bonne authentification, ou pas d'authentification du tout, ne sont jamais exposés directement.
Limites : Authelia ne recharge pas sa configuration à chaud ; il faut redémarrer le conteneur.
CrowdSec plutôt qu'un simple fail2ban sur le serveur
Choix : CrowdSec avec le bouncer intégré à SWAG. Le captcha passe par Cloudflare Turnstile.
Pourquoi : CrowdSec analyse les journaux de plusieurs services et bénéficie des listes de blocage communautaires. Le bouncer dans SWAG agit avant que la requête n'atteigne le service. Turnstile a été préféré à reCAPTCHA.
Limites :
- Turnstile impose de désactiver HTTP/2 côté SWAG.
- Sur Debian 13, sans rsyslog, il n'y a pas de fichier de journal d'authentification : CrowdSec ne voit pas SSH. rsyslog est donc réinstallé.
Le Raspberry Pi, lui, n'est pas exposé : un fail2ban limité à SSH y suffit.
docker-socket-proxy pour l'accès à l'API Docker
Choix : aucun conteneur ne monte le socket Docker directement pour la surveillance. docker-socket-proxy expose l'API en lecture seule, sur un réseau Docker dédié partagé uniquement avec n8n.
Pourquoi : accéder au socket Docker revient à être root sur l'hôte. Le proxy limite l'accès à la liste des conteneurs, sans aucune écriture.
DNS
DuckDNS
Choix : un sous-domaine DuckDNS mis à jour par un conteneur.
Pourquoi : gratuit, simple, et compatible avec la validation DNS de Let's Encrypt pour le certificat wildcard.
Limites acceptées : les serveurs DNS de DuckDNS sont parfois instables et le TTL est court, ce qui provoque des échecs d'accès intermittents.
Alternative envisagée : un domaine payant avec DNS chez Cloudflare. Plus fiable, pas encore fait.
AdGuard Home pour le hairpin NAT
Choix : AdGuard Home sur le Pi, avec une réécriture DNS wildcard du domaine public vers l'IP locale du serveur.
Pourquoi : réglé une fois pour tous les appareils du réseau, y compris les téléphones.
Alternative écartée : une entrée dans /etc/hosts sur chaque machine. Ça marche en dépannage, mais ça ne couvre ni les téléphones ni les nouveaux appareils.
Limites : si le Pi tombe, la résolution locale du domaine tombe avec lui.
Mises à jour
Watchtower, version fork
Choix : le fork nickfedor/watchtower sur les deux machines, mise à jour planifiée la nuit. Détails : Watchtower.
Pourquoi : le projet d'origine n'est plus maintenu.
Limites :
- Le fork refuse de démarrer avec
rolling-restartquand un conteneur a un depends_on ; l'option est donc retirée. - Le fork n'a pas d'API HTTP : les notifications passent par n8n (voir ci-dessous).
Exclusions de la mise à jour automatique
Choix : le reverse proxy, l'authentification, CrowdSec et les bases de données critiques sont exclus par le label com.centurylinklabs.watchtower.enable=false.
Pourquoi : une mise à jour ratée de ces briques coupe l'accès à tout le reste, ou peut abîmer des données. Elles se mettent à jour à la main, notes de version lues.
Bases de données épinglées sur une version majeure
Choix : chaque image de base de données porte une version majeure explicite, jamais latest.
Pourquoi : une montée de version majeure de MariaDB ou PostgreSQL peut demander une migration des fichiers. Épinglée, la base ne reçoit automatiquement que des correctifs mineurs.
Conséquence : les montées de version majeure sont planifiées, avec une copie des fichiers bruts avant l'opération.
Notifications de mises à jour par n8n
Choix : un workflow n8n interroge docker-socket-proxy à intervalle régulier et envoie les changements sur Telegram.
Pourquoi : le fork de Watchtower n'offre pas d'API, et n8n était déjà en place.
Sauvegarde
Plakar vers le Raspberry Pi
Choix : Plakar sur le serveur principal envoie chaque nuit vers un dépôt sur le Pi, en SFTP. Détails : Sauvegarde.
Pourquoi :
- Plakar déduplique et chiffre : après la première sauvegarde complète, les suivantes ne transfèrent que les changements, ce qui compte avec le débit Wi-Fi du Pi.
- Le dépôt est sur une autre machine que les données.
- Plakar est un logiciel libre français.
Limites : les deux machines sont au même endroit. Il n'y a pas encore de copie hors site.
Exports SQL avant chaque sauvegarde
Choix : chaque base est exportée en SQL juste avant la sauvegarde. Les dossiers de données des bases sont exclus.
Pourquoi : copier les fichiers d'une base en cours d'écriture donne une copie potentiellement incohérente. Un export SQL est cohérent et se restaure même sur une version différente du moteur.
Utilisateur SFTP dédié
Choix : le serveur se connecte au Pi avec un utilisateur réservé à la sauvegarde, limité à SFTP par ForceCommand internal-sftp.
Pourquoi : si la clé de sauvegarde fuite, elle ne donne pas de shell sur le Pi.
SSD plutôt que carte SD
Choix : le dépôt est sur un SSD USB, pas sur la carte SD du Pi.
Pourquoi : une carte SD supporte mal les écritures répétées et volumineuses.
Limites : le pont USB du boîtier décroche sous forte charge d'écriture. Contournement en place (UAS désactivé, parallélisme réduit) ; un hub USB alimenté est prévu. Détails : SSD de stockage.
Système
Debian stable sur les deux machines
Choix : Debian 13 sur le serveur et sur le Pi, y compris à la place de Raspberry Pi OS.
Pourquoi : préférence pour Debian. Raspberry Pi OS n'est qu'une adaptation de Debian : autant partir directement de la distribution d'origine, et avoir le même système et les mêmes habitudes sur les deux machines.
Dépôt Raspberry Pi limité par pinning
Choix : le dépôt Raspberry Pi est actif sur le Pi, mais un pinning APT le limite au noyau, au firmware et aux outils raspi. Détails : Noyau et dépôt Raspberry Pi.
Pourquoi : garder Debian pour tout le reste, tout en recevant les mises à jour du noyau et du firmware propres au Pi. Sans ce dépôt, le noyau et le firmware restent figés.
Noyau Zabbly sur le serveur
Choix : le noyau mainline de Zabbly à la place du noyau Debian. Détails : Noyau Zabbly.
Pourquoi : historique. À la mise en service du serveur, certains pilotes nécessaires n'étaient pas encore disponibles dans le noyau Debian.
Limites : un dépôt tiers de plus dans la chaîne de confiance.
À réévaluer : le noyau Debian a évolué depuis. Si les pilotes concernés y sont maintenant, le retour au noyau Debian supprime un dépôt tiers.
Pas de pip dans le Python système
Choix : pipx pour les outils en ligne de commande, un venv par script. Voir les règles communes de la page Infrastructure.
Pourquoi : une montée de version de Debian change la version de Python et casse tout ce qui a été installé avec pip dans le Python système.
Peu de dépôts tiers
Choix : un paquet disponible dans Debian s'installe depuis Debian. Un dépôt tiers n'est gardé que s'il apporte quelque chose d'introuvable ailleurs.
Pourquoi : chaque dépôt tiers est un point de confiance de plus, et il peut changer de conditions du jour au lendemain (passage payant, abandon).
Reconstruction documentée plutôt qu'image disque
Choix : pas d'image complète de la carte SD du Pi. La remise en service suit la page Reconstruction du Raspberry Pi.
Pourquoi : la configuration propre au Pi est sauvegardée chaque semaine par un script. Avec cette sauvegarde et la page de reconstruction, une carte neuve se remet en service sans dépendre d'une image qui vieillit à chaque modification.
Alertes
Choix : les alertes (sauvegarde, mises à jour de conteneurs) arrivent sur Telegram, par un bot.
Pourquoi :
- Envoyer un message ne demande qu'une requête HTTP vers l'API des bots (un simple curl dans un script), sans serveur supplémentaire à héberger.
- n8n a un nœud Telegram intégré.
- La notification arrive sur le téléphone, même hors du réseau local.
- Gratuit.
Alternatives écartées :
- E-mail : il faut un serveur SMTP ou un relais, et les messages automatiques finissent souvent en spam.
- Service auto-hébergé (ntfy, Gotify) : hébergé sur le serveur principal, il tombe avec lui, alors que c'est justement là qu'on a besoin d'être prévenu.
Limites :
- Dépendance à un service tiers. Les messages de bot ne sont pas chiffrés de bout en bout : ils ne contiennent donc que des états (réussite, échec, nom du conteneur), jamais de secret ni de détail sensible.
- Le jeton du bot est un secret : il est stocké hors du script, dans un fichier lisible par root seulement.
- Si le serveur principal est complètement arrêté, aucun message ne part. L'absence du message ✅ du matin est elle-même une alerte.