Cloud - Infra self-hosted IaC

Reprendre le contrôle sur son infrastructure : un VPS self-hosted pour comprendre chaque couche entre mon code et mes utilisateurs. Tout est automatisé, parce que la config manuelle ne scale pas, même pour un seul serveur.

III - Croissance 12 jours 2026-03-02 2026-03-14
XP
85%

Genèse

J’ai toujours hébergé mes projets chez des tiers. Vercel par-ci, Heroku par-là, un Supabase pour la base. Ça marche, mais on finit par éparpiller ses données chez cinq fournisseurs différents, sans vraiment comprendre ce qui tourne sous le capot. Quand un déploiement échoue sur un PaaS, on ouvre un ticket. Quand il échoue sur son propre serveur, on comprend pourquoi.

Début mars 2026, j’ai commandé un VPS Ubuntu vierge avec une idée simple : tout reconstruire from scratch, sur une seule machine, entièrement automatisé. Le déclencheur concret, c’est ComRenov. J’avais besoin d’héberger cette app quelque part, et plutôt que de prendre un PaaS de plus, j’ai décidé que ce serait l’occasion de monter la plateforme qui accueillerait tous mes projets sur tordu-jardin.fr. Un make deploy et l’ensemble de l’infra se déploie. Pas de clic dans une console web, pas de config manuelle. Juste des rôles Ansible et un Makefile.

Architecture

L’infra repose sur une quinzaine de services Docker orchestrés par 21 rôles Ansible. Chaque rôle est idempotent : on peut le rejouer dix fois, il ne casse rien. L’ensemble se déploie en une commande, ou rôle par rôle avec make deploy TAGS=monitoring quand on veut cibler un morceau précis.

En façade, Traefik sert de reverse proxy. Il découvre les conteneurs via les labels Docker et gère les certificats TLS automatiquement avec Let’s Encrypt. Derrière, trois réseaux isolés séparent le proxy, le monitoring et la base de données. C’est du defense-in-depth : même si un conteneur est compromis, il ne voit pas les autres réseaux. Le socket Docker n’est jamais exposé directement, un proxy read-only filtre les appels.

Côté observabilité, c’est la partie dont je suis le plus content. Prometheus collecte les métriques, Loki agrège les logs, Tempo stocke les traces distribuées, et Grafana affiche tout ça dans une dizaine de dashboards avec des SLOs et du calcul d’error budget. J’ai poussé jusqu’au RUM côté navigateur avec Faro pour avoir les Web Vitals et les erreurs JavaScript en temps réel. Alertmanager route les alertes vers une instance Ntfy self-hosted, donc les notifications arrivent sur mon téléphone sans dépendre d’un service externe.

Ce qui rend l’infra intéressante

Ce n’est pas un homelab bricolé. J’ai emprunté les pratiques SRE qu’on utilise en entreprise et je les ai appliquées à un VPS perso. Pas pour le flex, mais parce que c’est le meilleur endroit pour apprendre : en production professionnelle, l’infra est déjà en place et les choix sont faits. Ici, je peux tout construire de zéro, casser des choses, et comprendre pourquoi ces pratiques existent. Chaque conteneur a un healthcheck, des limites de ressources, et le flag no-new-privileges. Les backups Restic tournent vers Scaleway S3, et PostgreSQL a du Point-In-Time Recovery via WAL-G pour pouvoir restaurer la base à n’importe quel instant.

SSH est accessible uniquement via le tunnel WireGuard. Fail2ban exporte ses métriques vers Prometheus, donc je vois les tentatives d’intrusion dans Grafana. Tous les secrets vivent dans un vault Ansible, et un playbook vérifie avant chaque déploiement qu’aucun placeholder CHANGE_ME ne traîne dans les variables. Pour le CI/CD, j’ai itéré trois fois en moins de deux heures avant de trouver la bonne approche : l’API Portainer avec un token scopé, qui donne au runner GitLab juste ce qu’il faut sans exposer le socket Docker.

La fiabilité de l’ensemble est validée par dr-test, qui simule des scénarios catastrophe dans une VM jetable et mesure le temps de reconstruction complète. L’infra sert déjà de socle pour ComRenov et Basalt Beholder, avec un rôle app-template générique prêt à accueillir les prochains projets.

Journal

Du VPS vierge à une infra fonctionnelle

Tout a commencé un soir de mars. En quelques heures, le scaffold complet était en place : hardening SSH, firewall deny-all, Docker, Traefik avec TLS auto, la stack monitoring au complet, Authentik en SSO centralisé, et les premières apps. Le genre de soirée où tu ne vois pas le temps passer.

Le marathon du 5 mars

La journée la plus intense du projet. PostgreSQL s’installe sur la machine hôte avec une isolation réseau hub & spoke, une suite de smoke tests vérifie que chaque service répond correctement, et les premiers dashboards SLO apparaissent. L’après-midi, j’ajoute le tracing distribué avec Tempo et le RUM navigateur avec Faro. Le debug du pipeline Faro vers Loki m’a donné du fil à retordre, mais en fin de journée le monitoring passait de “ça collecte des métriques” à une observabilité complète.

Hardening et backup

Un sprint dédié à la solidité. Chaque conteneur reçoit ses limites de ressources et ses flags de sécurité. Les backups Restic sont configurés vers S3 avec une rétention 7j/4s/6m. PostgreSQL obtient le PITR via WAL-G. Et un petit service Flask, le pg-provisioner, permet de créer des bases à la volée pour les nouvelles apps sans toucher manuellement au serveur.

Le pipeline CI/CD en trois tentatives

J’ai cherché comment déployer automatiquement depuis GitLab. D’abord les webhooks Portainer, trop fragiles. Puis le mount du Docker socket dans le runner, trop permissif. Finalement, l’API Portainer avec un token scopé a trouvé le bon équilibre : le CI n’a accès qu’à ce dont il a besoin, pas au socket Docker.

Consolidation

Retour après quelques jours de pause. Le pipeline CI révèle ses failles en production : stacks qui ne se recréent pas, cache Docker qui bloque les mises à jour. Le tunnel WireGuard tombait silencieusement, corrigé par un watchdog systemd. Le GitLab Runner passe d’un bricolage à un vrai rôle Ansible. C’est à ce moment-là que le projet atteint sa forme finale : 21 rôles et une infra qu’on peut reconstruire de zéro en une commande.

Stack technique

Ansible

Provisioning IaC

Reconstruire le serveur de zéro en une commande

Docker

Containerisation

Isoler les services, garantir la reproductibilité

Traefik

Reverse proxy + TLS auto

Routage automatique vers les conteneurs, TLS sans config

Prometheus + Grafana

Observabilité

Comprendre ce qui se passe avant que ça tombe

Consolidation : CI, tunnel, monitoring+15 commits

Fix du pipeline CI/CD (ForceRecreate, cache busting). WireGuard watchdog pour recovery automatique du tunnel. GitLab Runner en rôle Ansible complet. Tunnel frp pour les environnements de dev. Pushgateway, revamp RUM dashboard. Versions épinglées, test inventory local.

  • CI : ForceRecreate, COMMIT_SHA build arg, DOCKER_NO_CACHE
  • WireGuard watchdog service + persistent keepalive
  • GitLab Runner : rôle Ansible complet avec Docker Compose + prune timer
  • Tunnel frp : rôle serveur + script client
  • Pushgateway + revamp RUM dashboard + bump Tempo/Alloy
  • Bump versions, pin Ansible collections, CLAUDE.md, test inventory Multipass
Pipeline CI/CD GitOps+6 commits

Pipeline self-service GitOps avec onboarding automatisé. Trois itérations en 1h20 : webhooks Portainer → Docker socket → API Portainer. Hardening firewall et socket-proxy.

  • Pipeline CI self-service avec script d onboarding
  • Deploy via Portainer API (PUT /api/stacks/{id})
  • Hardening firewall, fail2ban, socket-proxy
Ntfy self-hosted, alerting complet+5 commits

Ntfy en rôle Ansible avec relay Alertmanager custom. Couverture alerting complète : Grafana, Authentik, WAL-G. Page 404 catch-all. Fix SSO Authentik + réseau monitoring. Support deploy key CI.

  • Ntfy self-hosted avec relay Alertmanager custom
  • Alerting full coverage : Grafana, Authentik, WAL-G
  • Page 404 catch-all + homepage updates
  • Authentik SSO routing + réseau monitoring
WireGuard VPN, homepage+2 commits

VPN WireGuard pour accès SSH sécurisé, firewall durci. Homepage statique avec liens vers tous les services.

  • WireGuard VPN : SSH via tunnel uniquement
  • Homepage : dashboard statique avec liens services
Hardening, PITR, self-service DB+12 commits

Sprint sécurité l après-midi : vault validation pré-deploy, healthchecks et no-new-privileges sur tous les conteneurs, limites de ressources. Backup Restic vers Scaleway S3. PostgreSQL PITR via WAL-G. pg-provisioner pour créer des bases à la volée.

  • Vault validation pré-deploy (pas de CHANGE_ME en prod)
  • SSH hardening, sudoers restriction, Docker metrics bind localhost
  • Healthchecks, no-new-privileges, resource limits sur tous les conteneurs
  • Alerting : container, monitoring-health, app alert rules
  • Backup Restic → Scaleway S3 + timer systemd
  • PostgreSQL PITR via WAL-G vers Scaleway
  • pg-provisioner : création de bases à la volée pour les nouvelles apps
PostgreSQL, observabilité, tracing distribué+23 commits

PostgreSQL en host avec isolation réseau. Smoke tests pour valider chaque rôle. Dashboards SLO/error budget pour suivre la fiabilité. Tracing distribué Tempo + Alloy + RUM Faro pour comprendre le parcours utilisateur de bout en bout.

  • PostgreSQL host avec network isolation hub & spoke
  • Smoke tests pour valider chaque rôle après déploiement
  • Dashboard SLO/error budget + blocage web scanners
  • Fail2ban → Prometheus metrics exporter + dashboard Grafana
  • Docker registry privé + rôle ComRenov
  • Tracing distribué : Tempo + Alloy + RUM Faro (Web Vitals, JS errors)
  • 8 dashboards Grafana organisés en dossiers Infrastructure / ComRenov
  • Pipeline Faro→Loki, Promtail JSON parsing, Pino level mapping
Portainer OIDC natif+1 commits

Portainer passe de forwardAuth à OIDC natif via Authentik. Blueprint SSO étendu avec client Portainer.

  • Portainer : switch forwardAuth → OIDC natif via Authentik
Jour 1 : les fondations+10 commits

Scaffold complet après plusieurs jours de préparation. Hardening SSH, fail2ban, UFW deny-all, Docker. Traefik reverse proxy avec TLS auto. Stack monitoring Prometheus/Grafana/Loki. Authentik SSO centralisé. Objectif : un serveur verrouillé par défaut avec observabilité dès le départ.

  • Scaffold : inventory, playbook, Makefile, cloud-config
  • Hardening SSH + fail2ban + UFW deny-all + Docker
  • Traefik reverse proxy + TLS auto + socket proxy read-only
  • Prometheus + Grafana + Loki + Promtail + cAdvisor
  • Alertmanager + backup Restic S3/B2
  • Authentik SSO (blueprints) + Nextcloud OIDC
  • Portainer + Uptime Kuma