Le firewall Docker qui cassait `manabo`
Pendant 3 jours, manabo.cookie renvoyait 502. La cause se cachait dans une règle UFW que je n'avais jamais regardée.
manabo.cookie répond systématiquement 502 Bad Gateway. Le container manabo lui-même tourne et répond bien sur localhost:3456 depuis l'hôte. Caddy log : 'dial tcp 172.17.0.1:3456: i/o timeout'.
Caddy (en container Docker) atteint l'hôte via host.docker.internal qui résout vers 172.17.0.1. Mais UFW est en default deny et bloque les paquets venant du range Docker (172.16.0.0/12).
sudo ufw allow from 172.16.0.0/12 to any port 3456 proto tcp comment 'manabo from Docker'
flowchart LR
Client(["Client<br/>browser"]) -->|HTTPS| Caddy["Caddy<br/>container Docker"]
Caddy -->|"host.docker.internal:3456<br/>(172.17.0.1)"| UFW{{"UFW<br/>default deny"}}
UFW -.->|"❌ DROP<br/>(aucune règle)"| X[/timeout/]
UFW ==>|"✅ allow 172.16/12<br/>(après fix)"| Manabo["manabo<br/>host service :3456"]
style X fill:#FF5E78,color:#0E0E10
style Manabo fill:#2ECC71,color:#0E0E10 Le symptôme
Vendredi soir. Je remarque par hasard que manabo.cookie répond 502. Bizarre, j’avais rien touché.
SSH sur cookie-server, premiers checks :
docker ps | grep manabo# manabo container — Up 23 days (healthy) ✓
curl localhost:3456/health# {"status":"ok"} ✓
curl http://manabo.cookie/health# (long timeout) ... 502 Bad Gateway ✗Donc le service tourne. C’est Caddy qui n’arrive plus à l’atteindre.
L’enquête
Logs Caddy :
docker logs caddy-1 --tail 20 | grep manabo# {"level":"error","msg":"dial tcp 172.17.0.1:3456: i/o timeout"}172.17.0.1 c’est l’IP de l’hôte vue depuis le réseau Docker (le host.docker.internal du Mac, version Linux). Caddy essaie de pousser la requête à l’hôte mais elle se perd.
Le service écoute bien :
ss -tlnp | grep 3456# LISTEN 0 511 *:3456 *:* users:(("node",pid=...))Sur *:3456 donc accepte les connexions de partout. Le node qui écoute c’est bien manabo (vérifié avec lsof -p).
Donc :
- ✓ Le service écoute
- ✓ Caddy envoie la requête vers la bonne IP/port
- ✗ La requête ne revient jamais
C’est un firewall qui bloque.
Le coupable
sudo ufw status verbose# Status: active# Default: deny (incoming), allow (outgoing), deny (routed)## To Action From# -- ------ ----# 22/tcp ALLOW Anywhere# 80,443/tcp ALLOW Anywhere# (...)UFW est en default deny côté incoming. Aucune règle ne couvre le port 3456 ni la range Docker.
Les paquets de Caddy (qui arrivent sur 172.17.0.1:3456 depuis le sous-réseau Docker 172.17.0.0/16) sont silencieusement droppés. D’où le timeout.
Mais pourquoi ça marchait avant ? J’ai dû modifier UFW un soir sans m’en souvenir — probablement en faisant le ménage des règles obsolètes après une migration de service. J’ai dû supprimer une règle générique qui couvrait ce cas.
Le fix
sudo ufw allow from 172.16.0.0/12 to any port 3456 proto tcp \ comment 'manabo from Docker'sudo ufw reloadL’état de la table UFW avant/après le fix :
Status: active
To Action From
-- ------ ----
[ 1] 22/tcp ALLOW IN Anywhere
[ 2] 80,443/tcp ALLOW IN AnywhereStatus: active
To Action From
-- ------ ----
[ 1] 22/tcp ALLOW IN Anywhere
[ 2] 80,443/tcp ALLOW IN AnywhereStatus: active
To Action From
-- ------ ----
[ 1] 22/tcp ALLOW IN Anywhere
[ 2] 80,443/tcp ALLOW IN Anywhere
[ 3] 3456/tcp ALLOW IN 172.16.0.0/12 # manabo from DockerStatus: active
To Action From
-- ------ ----
[ 1] 22/tcp ALLOW IN Anywhere
[ 2] 80,443/tcp ALLOW IN Anywhere
[ 3] 3456/tcp ALLOW IN 172.16.0.0/12 # manabo from DockerPourquoi 172.16.0.0/12 et pas 172.17.0.0/16 ? Parce que Docker peut utiliser plusieurs ranges (172.17.x, 172.18.x, etc. selon les networks créés). Le /12 couvre toute la plage Docker conventionnelle (172.16.0.0 à 172.31.255.255).
Curl de validation :
curl http://manabo.cookie/health# {"status":"ok"} ✓3 jours d’indispo pour un service que peu de gens utilisent — pas catastrophique mais ça me fait râler.
La leçon
J’ai depuis ajouté un script qui ouvre automatiquement tous les ports host-direct utilisés par Caddy :
#!/usr/bin/env bashPORTS=$(docker exec caddy-1 cat /etc/caddy/Caddyfile \ | grep -oP 'host\.docker\.internal:\K\d+' \ | sort -u)
for port in $PORTS; do sudo ufw allow from 172.16.0.0/12 to any port $port proto tcp \ comment "caddy → host:$port" 2>/dev/null || truedonesudo ufw reloadLancé après chaque modif du Caddyfile. Si un jour j’ajoute un nouveau service host-direct, plus jamais de timeout silencieux.
Chargement…