---
title: "Trente conteneurs, trente portes — la carte du VPS"
subtitle: "On croyait connaître la prod. En ouvrant le vrai Caddyfile du serveur, 22 sous-domaines sont apparus, plus quatre autres cachés dans des imports — et sept « pannes » qui n'en étaient pas."
date: 2026-10-01
time: "17:32"
author: VFG
publishedBy: code
status: pub
tags: ["infra", "vps", "caddy", "prod", "cartographie", "sous-domaines", "citadelle", "metaprojet"]
---

## TL;DR

Le VPS VFG, c'est **30 conteneurs actifs**, **~30 sous-domaines publics**, **50 sockets en écoute**. On croyait que le routage vivait dans un fichier — il vit dans **cinq**, reliés par des `import` du Caddyfile racine.

Et c'est là que les surprises arrivent : **`citadelle.vfg.lol` ne répond pas alors que le service tourne sur le serveur**. **`matrice.vfg.lol` n'existe pas — c'est `clean.vfg.lol`.** **`gandalf` est en 404 parce que son backend web est éteint.** Et deux « 404 » sont en réalité des services **parfaitement vivants** qui n'ont simplement rien à dire sur `/`.

Bilan : sur sept trous apparents, **trois pannes réelles, deux faux positifs, deux services vivants non exposés**.

---

## 1. Ce qu'on croyait vs ce qui est

Nous avions un repo `vps-infra` — GitOps, Ansible, Caddy. Sauf que son `Caddyfile` est un **template** :

```
mcp.{$BASE_DOMAIN} {
    reverse_proxy mcp-bridge:8000
}
```

`{$BASE_DOMAIN}` — une variable. Autrement dit : **la carte qu'on avait sous la main n'était pas la prod.** Il a fallu ouvrir le serveur.

```bash
ssh debian@51.77.244.222 'sudo cat /etc/caddy/Caddyfile'
```

## 2. Le routage est en cinq morceaux

```caddy
{
	admin off
}
import /etc/caddy/lucien.caddy      # lucien.best + www
import /etc/caddy/vfg-fleet.caddy   # 22 vhosts *.vfg.lol
import /etc/caddy/vfg-admin.caddy   # admin.vfg.lol (Mission Control)
import /etc/caddy/zevent.caddy      # zevent.vfg.lol
import /etc/caddy/jah.caddy         # jah.vfg.lol
```

**Leçon immédiate :** chercher le routage d'un serveur dans **un seul** fichier est un piège. Un `Caddyfile` racine est souvent un **index d'imports**. Qui lit la racine seule voit cinq lignes et croit tout savoir.

## 3. La carte

Une trentaine de domaines, chacun derrière un upstream en `127.0.0.1` — les conteneurs ne sont **jamais** exposés directement :

| Domaine | Upstream | Auth |
|---|---|---|
| `hero.vfg.lol` / `hero-api` | :8081 / :8082 | app |
| `gate.vfg.lol` / `gate-api` | :8083 / :8084 | **Basic** |
| `clean.vfg.lol` / `clean-api` | :8086 / :8085 | — |
| `admin.vfg.lol` | hub admin + portainer/cockpit/netdata/dozzle | **Basic + Tailscale-only** |
| `hub.vfg.lol` / `hub-api` | :4319 / :4320 | **Basic** |
| `mcp-docs` / `mcp-feed` / `mcp-vfg` | :4340 / :4341 / :4342 | — |
| `pulse` / `ideas` / `grimoire` | :5194 / :5192 / :5193 | partiel |
| `msn` / `msnplus` | :5210 / :5221 | — |
| `gandalf.vfg.lol` | :5198 + les 3 MCP sous `/vfg-*-mcp` | — |
| `kit` / `blog` / `timeline` / `poc` / `zevent` | :8091 / :8092 / :8095 / :8093 / :5200 | — |
| `jah.vfg.lol` | :5240 | — |
| `lucien.best` | :3000 | — |
| `vfg.lol` | **redir → hero** | — |

**Point de sûreté :** `admin.vfg.lol` n'est pas seulement derrière un mot de passe — il est **bloqué hors Tailscale** (`remote_ip 100.64.0.0/10` → 403). Et le Caddyfile le dit noir sur blanc : *« Portainer/Grafana : jamais de vhost public »*. Tenir cette promesse dans la config, pas seulement dans la doc, c'est rare et c'est bien.

## 4. Les sept trous — et ce qu'ils cachent

C'est le cœur de l'exercice. Chaque URL qui échoue a été tracée jusqu'à son upstream.

### Trois vraies pannes

| URL | Ce que dit la mesure |
|---|---|
| `timeline.vfg.lol` → **502** | vhost → `:8095`, **mais `:8095` n'écoute pas** — le conteneur `t3-timeline` est arrêté |
| `gandalf.vfg.lol` → **404** | vhost → `:5198`, **qui n'écoute pas** (seul `:5199` répond) — le backend web de Gandalf est **éteint** |
| `msn.vfg.lol` → **502** | vhost → `:5210`, **muet** — le MSN legacy a été remplacé par **`msnplus` (`:5221`)** |

### Deux faux positifs

| URL | Ce que dit la mesure |
|---|---|
| `mcp-docs.vfg.lol` → 404 | `:4340` **écoute**. Un serveur **MCP** ne répond pas sur `/` — son endpoint est `/sse` ou `/mcp`. **Il va très bien.** |
| `clean-api.vfg.lol` → 404 | `:8085` **écoute**. L'API n'a **pas de route racine**. **Elle va très bien.** |

> Un « 404 » sur un service up n'est pas une panne : c'est **une question mal posée**. Sonder `/` sur une API ou un MCP, c'est frapper à une porte qui n'existe pas et conclure que la maison est vide.

### Deux vivants non exposés

| URL | Ce que dit la mesure |
|---|---|
| `citadelle.vfg.lol` → ERR | **`127.0.0.1:6767` écoute sur le VPS.** La Citadelle **tourne déjà en prod** — elle n'a simplement **aucun vhost**. Il manque quatre lignes de Caddy. |
| `matrice.vfg.lol` → ERR | **Aucun vhost `matrice`** — la Matrice est exposée sous **`clean.vfg.lol`** et **`clean-api.vfg.lol`**. |

La dernière ligne est la plus instructive : **on cherchait un service sous le nom qu'on lui donne dans nos têtes, pas sous le nom qu'il porte dans la config.**

## 5. Ce que ça dit de nos méthodes

Trois réflexes ont produit des faux constats, et les trois sont **déjà** dans notre liste de leçons :

1. **Lire un fichier au lieu du système** — le `Caddyfile` racine n'est qu'un index d'imports.
2. **Confondre « pas de réponse » et « service mort »** — un 404 sur `/` peut être un service en pleine santé. *« 0 résultat n'est pas une réponse »* (méthode d'audit, §3).
3. **Chercher sous le mauvais nom** — `matrice` s'appelle `clean`. C'est la version infra de *« vérifier toute absence déclarée »* : un service « absent » l'est souvent sous un autre nom.

Et une quatrième, plus profonde : **le repo GitOps ne contenait pas la prod**. Le template `{$BASE_DOMAIN}` décrivait l'infra **telle qu'on voulait la concevoir**, pas **telle qu'elle tourne**. C'est exactement la dérive « la prose n'est plus régénérée depuis la mesure » — appliquée au serveur.

## 6. À faire (rien exécuté)

- **Décider** d'exposer `citadelle.vfg.lol` (le service tourne, il manque le vhost) — ou d'assumer local-only.
- **Réparer ou retirer** : `timeline` (:8095 down), `gandalf` web (:5198 down), le vhost `msn` (→ `msnplus`).
- **Versionner le vrai Caddyfile** (`/etc/caddy/*.caddy`) dans `vps-infra` — pour que le GitOps cesse de mentir.
- **Outiller** : aucun outil ne répond aujourd'hui à « qu'est-ce qui tourne, local **et** prod ? ». Ce matin, il a fallu le faire à la main.

## 7. Moral

On a compté **trente conteneurs** et **trente portes**. Sept semblaient fermées. En ouvrant chacune, on a trouvé **trois maisons vides**, **deux portes qui n'existaient pas**, et **deux maisons habitées dont personne ne connaissait l'adresse**.

**Un service « down » n'est pas toujours mort. Il est parfois vivant sous un autre nom, ou derrière une porte qu'on n'a pas frappée.**

---

*Mesuré en lecture seule sur `debian@51.77.244.222` le 2026-10-01. Carte complète : `CARTE-PROD-VPS-2026-10-01.md`. Aucun conteneur redémarré, aucune config modifiée.*