TL;DR
Le 2026-09-05, https://lucien.best était injoignable en HTTPS (tlsv1 alert internal error / SEC_E_ILLEGAL_MESSAGE) alors que :
- le DNS
Apointait bien vers le VPS51.77.244.222; lucien-site.serviceétait actif ;http://127.0.0.1:3000/renvoyait 200.
Cause racine : le /etc/caddy/Caddyfile modifié le 2026-07-08 ne contenait plus que :
{
admin off
}
import /etc/caddy/vfg-fleet.caddy
import /etc/caddy/vfg-admin.caddy
Les blocs lucien.best / www.lucien.best (historiquement no-touch) avaient disparu. Sans site Caddy pour ce SNI, Caddy refuse le handshake TLS → symptôme « SSL cassé », pas « app down ».
Fix : restaurer un snippet /etc/caddy/lucien.caddy + systemctl restart caddy (pas reload : voir plus bas). Certificat Let's Encrypt réémis le jour même. Smoke : lucien.best / hero.vfg.lol / msn.vfg.lol / blog.vfg.lol en 200.
Bonus session : DNS zevent.vfg.lol déjà prêt → déploiement ZDASH (fg-zevent, :5200, vhost Caddy) live sur https://zevent.vfg.lol.
Chronologie
| Heure (approx, CEST) | Événement |
|---|---|
| ~12:09 | Signal FG : domaine zevent.vfg.lol ajouté ; lucien.best ne marche plus |
| ~12:10 | Probes Windows : DNS OK pour lucien + zevent ; HTTPS échoue ; hero.vfg.lol OK |
| ~12:12 | SSH debian@ : app Lucien OK en local ; openssl SNI lucien.best → no peer certificate |
| ~12:13 | Lecture Caddyfile : aucun lucien dans /etc/caddy/ actif |
| ~12:14 | Source intacte trouvée : /opt/lucien/deploy/Caddyfile |
| ~12:17 | Tentative systemctl reload caddy → échec (admin off → API :2019 refusée) ; process Caddy reste sur l'ancienne config (fleet intact) |
| ~12:19 | systemctl restart caddy → cert LE pour lucien.best ; HTTPS 200 |
| ~12:20–12:21 | Upload + build fg-zevent, compose up, import zevent.caddy, restart Caddy → zevent.vfg.lol 200 |
Symptômes (ce que ça donnait vraiment)
Côté client
curl https://lucien.best/
→ curl: (35) ... tlsv1 alert internal error
# Windows / schannel
SEC_E_ILLEGAL_MESSAGE (0x80090326)
HTTP clair répondait encore avec un redirect Caddy vers HTTPS :
curl -I http://lucien.best/
→ 308 Location: https://lucien.best/
Donc « le domaine répond » en HTTP, mais tout navigateur moderne casse au TLS.
Côté VPS (preuves)
| Check | Résultat |
|---|---|
systemctl is-active lucien-site | active |
ss :3000 | 127.0.0.1:3000 LISTEN |
curl http://127.0.0.1:3000/ | 200 |
curl -k https://lucien.best/ | échec TLS (pas de cert pour le SNI) |
openssl s_client -servername lucien.best | no peer certificate available, alert 80 |
openssl s_client -servername hero.vfg.lol | chaîne LE valide (YE2) |
grep -R lucien /etc/caddy/*.caddy (actifs) | vide |
Signature diagnostique à retenir :
App up + DNS OK + TLS alert sans certificat peer = vhost Caddy manquant (ou SNI non servi), pas un crash Node.
Cause racine détaillée
1. Perte des vhosts Lucien au 2026-07-08
stat /etc/caddy/Caddyfile :
- Modify / Birth : 2026-07-08 00:34
- Contenu réduit à
admin off+ imports fleet/admin
Backup de session du même jour (/opt/vfg-fleet/backups/session-20260708-010154/Caddyfile) : même contenu minimal — la perte est déjà dans l'historique ops de ce jour-là, pas une corruption du 5 septembre.
La doc fleet (VFVFGPT/deploy/vps/README.md) exigeait explicitement :
Ne pas toucher aux blocs
lucien.best/stats.lucien.bestdans/etc/caddy/Caddyfile.
Le pattern d'origine (setup-vps-host.sh) était : ajouter un import fleet au Caddyfile Lucien existant, pas remplacer le Caddyfile par « fleet only ».
2. Pourquoi hero.* marchait encore
Les vhosts *.vfg.lol vivent dans /etc/caddy/vfg-fleet.caddy, toujours importé. Lucien n'y a jamais dû être : il est hors fleet (systemd natif /opt/lucien, no-touch). Quand on « nettoie » le Caddyfile principal pour ne garder que les imports fleet, on coupe Lucien sans toucher au reste — d'où l'illusion que « Caddy va bien ».
3. Piège ops : admin off ⇒ reload impossible
Le Caddyfile commence par :
{
admin off
}
Conséquence :
caddy reload --config /etc/caddy/Caddyfile
→ Error: Post "http://localhost:2019/load": dial tcp [::1]:2019: connect: connection refused
systemctl reload caddy échoue (ExecReload = caddy reload), mais le daemon continue avec l'ancienne config en mémoire. C'est trompeur : on croit « reload KO = tout cassé », alors que la fleet reste servie.
Sur ce VPS, toute évolution Caddyfile exige systemctl restart caddy, avec une courte coupure TLS globale.
Drop-in utile à connaître : /etc/systemd/system/caddy.service.d/no-resume.conf force caddy run --config /etc/caddy/Caddyfile (pas de resume state).
Correctif appliqué (rejouable)
Ops via debian@51.77.244.222 (sudo NOPASSWD). Le user deploy est dans docker mais sans sudo passwordless et sans écriture sur /opt/vfg-fleet / /etc/caddy.
A. Restaurer Lucien (sans stats GoatCounter)
GoatCounter / :8088 était inactif → on n'a pas remis stats.lucien.best (évite un vhost ACME + 502 inutile). Source de vérité app : /opt/lucien/deploy/Caddyfile.
Fichier créé : /etc/caddy/lucien.caddy
lucien.best, www.lucien.best {
encode gzip zstd
reverse_proxy 127.0.0.1:3000
header {
X-Content-Type-Options nosniff
X-Frame-Options DENY
X-XSS-Protection "1; mode=block"
Referrer-Policy strict-origin-when-cross-origin
Permissions-Policy "interest-cohort=()"
X-Permitted-Cross-Domain-Policies none
-Server
}
@images path /images/*
header @images Cache-Control "public, max-age=2592000"
log {
output file /var/log/caddy/lucien.log {
roll_size 20mb
roll_keep 5
}
}
}
Caddyfile principal :
{
admin off
}
import /etc/caddy/lucien.caddy
import /etc/caddy/vfg-fleet.caddy
import /etc/caddy/vfg-admin.caddy
Puis :
sudo cp -a /etc/caddy/Caddyfile /etc/caddy/Caddyfile.bak-pre-lucien-restore-<TS>
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl restart caddy # PAS reload
# smoke
curl -sS -o /dev/null -w "%{http_code}\n" https://lucien.best/
curl -sS -o /dev/null -w "%{http_code}\n" https://hero.vfg.lol/
Preuve cert post-fix :
subject=CN = lucien.best
notBefore=Sep 5 09:21:15 2026 GMT
notAfter=Dec 4 09:21:14 2026 GMT
B. Prep / go-live zevent.vfg.lol (même session)
Prérequis DNS déjà là : zevent.vfg.lol A → 51.77.244.222 (pas de wildcard *.vfg.lol).
- Tarball
zevent-dash→/opt/vfg-fleet/repo/zevent-dash/ docker build -t fg-zevent:latest …compose/t3-zevent.yml+env/zevent.env(ADMIN_TOKENgénéré sur le VPS, hors git)docker compose … up -d→vfg-fleet-zevent-1sur127.0.0.1:5200- Snippet
/etc/caddy/zevent.caddy+ import dans le Caddyfile restart caddy→ ACME + reverse_proxy
Healthz public (extrait) : {"ok":true,…,"goals":{"participations":338,…}}.
Règles anti-régression (pour ne plus reproduire)
Checklist avant toute édition Caddy sur ce VPS
- Backup horodaté de
/etc/caddy/Caddyfileet des snippets touchés. grep -n lucien /etc/caddy/Caddyfile /etc/caddy/*.caddy— doit rester non vide tant que Lucien est hébergé ici.- Ne jamais remplacer le Caddyfile par « imports fleet only ». Pattern correct : Lucien (ou snippets no-touch) + import fleet + import admin.
caddy validateavant application.- Appliquer avec
systemctl restart caddy, pasreload, tant queadmin offest en place. - Smoke obligatoire après coup, dans cet ordre :
https://lucien.best/https://hero.vfg.lol/https://msn.vfg.lol/https://blog.vfg.lol/- le nouveau vhost le cas échéant
- Si un nouveau sous-domaine
*.vfg.lolest ajouté en DNS : créer le vhost Caddy le même jour (sinon même symptôme TLS que Lucien / zevent avant prep).
Ce qu'il ne faut pas faire
| Anti-pattern | Pourquoi ça fait mal |
|---|---|
| « On simplifie le Caddyfile, Lucien est documenté no-touch donc ça ira » | No-touch n'est pas magique : si le bloc n'est plus importé, il est mort |
Se fier à systemctl reload alors que admin off | Échec silencieux pour l'opérateur ; ancienne config reste en RAM |
| Diagnostiquer « HTTPS down » en ne testant que l'app locale | On rate 100 % des pannes edge |
Utiliser deploy@ pour éditer /etc/caddy | Pas de sudo NOPASSWD → scripts qui pendent sur mot de passe |
Remettre stats.lucien.best sans GoatCounter | ACME + reverse_proxy vers :8088 mort = bruit et 502 |
docker compose … --remove-orphans en lançant seulement t3-zevent.yml | Risque de cueillir des « orphans » qui sont en fait le reste de la fleet |
Structure cible recommandée (modulaire)
/etc/caddy/Caddyfile # global options + imports UNIQUEMENT
/etc/caddy/lucien.caddy # no-touch mémorial
/etc/caddy/vfg-fleet.caddy # *.vfg.lol applicatifs
/etc/caddy/vfg-admin.caddy # surfaces admin
/etc/caddy/zevent.caddy # ZDASH (éphémère / événement)
Leçon Citadelle (déjà dans les commentaires VPS, 2026-06-30) : snippets séparés = récupération rapide. Même leçon pour Lucien.
Accès SSH ops (rappel)
| User | Usage | sudo |
|---|---|---|
debian | edits Caddy, /opt/vfg-fleet, systemctl | NOPASSWD |
deploy | docker group, CI éventuelle | mot de passe requis ; peu d'écriture fleet |
Alias local utile : Host vfg-vps → deploy@51.77.244.222 (identité ~/.ssh/id_ed25519). Pour Caddy : préférer explicitement debian@51.77.244.222.
État final vérifié (2026-09-05 ~12:21 CEST)
| URL | Code | Note |
|---|---|---|
https://lucien.best/ | 200 | cert LE frais |
https://zevent.vfg.lol/ | 200 | ZDASH |
https://zevent.vfg.lol/healthz | 200 | JSON ok |
https://hero.vfg.lol/ | 200 | non régressé |
https://blog.vfg.lol/ | 200 | non régressé |
lucien-site.service | active | inchangé |
caddy.service | active | restart appliqué |
Hors scope volontaire : restauration stats.lucien.best (GoatCounter), durcissement sudo deploy, réactivation API admin Caddy (admin off).
Liens utiles
- Source Caddy Lucien :
/opt/lucien/deploy/Caddyfile(repoLucien/deploy/) - Doc fleet no-touch :
VFVFGPT/deploy/vps/README.md§ « Ce qu'il ne faut pas toucher » - Runbook ZDASH :
Zevent2026/zevent-dash/README.md§ déploiement VPS - Snippet Caddy ZDASH :
zevent-dash/caddy-snippet.txt