Mise à jour (2026-10-04) : ajout de la requête SQL qui vérifie la validation d’un serveur, de celle qui montre la clé SSH réellement associée, et du test de port à lancer depuis le conteneur
coolify.
J’intègre srv-b (VPS prod) à Coolify (sur srv-a) pour tout piloter depuis une UI. Premier candidat : Plausible Analytics, jusqu’ici en docker-compose à la main dans /opt/plausible/ derrière Caddy. Sur le papier, 6 phases. En vrai, Coolify v4 m’attrape 5 fois en 30 min.
Piège 1 — Le user par défaut, c’est coolify
L’UI demande IP + port SSH + clé. Validate → Permission denied (publickey,password). Tu revérifies ta clé dans /root/.ssh/authorized_keys. Sauf que SELECT user FROM servers WHERE name='srv-b' renvoie coolify : le user suggéré par défaut, c’est coolify, pas root. La base répond plus vite que l’UI.
Piège 2 — La mauvaise clé SSH
Coolify nomme ses clés avec un slug aléatoire (dull-dotterel-t27..., yellowed-yacare-mxpw...). Tu génères une clé, la poses sur le serveur, puis dans le dropdown tu prends la mauvaise — les noms se ressemblent. Renomme tes clés coolify-to-<server> dès création. Pour voir ce qui est vraiment associé au serveur :
SELECT s.name, s.user, pk.name AS key_name
FROM servers s
LEFT JOIN private_keys pk ON pk.id = s.private_key_id
WHERE s.name = 'srv-b';
⚠️ C’est le conteneur coolify qui ouvre la connexion SSH, pas l’hôte. Un nc -zv lancé depuis srv-a ne prouve rien ; le test se fait depuis le conteneur :
sudo docker exec coolify nc -zv 10.8.0.10 2222
Piège 3 — Proxy: None n’existe pas vraiment
Je choisis Proxy: None pour valider le serveur sans que Coolify installe Traefik (Caddy occupe encore 80/443). Validate → erreur 500 : Proxy should not run. You selected the Custom Proxy. (CheckProxy.php:36).
validateDockerVersion() cascade sur CheckProxy::run() qui throw quand proxy.type=NONE. Mais en base, is_reachable et is_usable sont à t : l’event ServerValidated passe juste avant le throw, le serveur est validé. Cosmétique, on continue.
La requête qui tranche, une ligne par serveur :
sudo docker exec coolify-db psql -U coolify -d coolify -c \
"SELECT s.name, s.ip, s.port, s.user, ss.is_reachable, ss.is_usable, s.proxy->>'type' AS proxy
FROM servers s JOIN server_settings ss ON ss.server_id = s.id;"
is_reachable et is_usable à t, plus le type de proxy voulu : le serveur est prêt à recevoir des ressources, erreur 500 ou pas.
Piège 4 — Pas d’onglet « Domains » pour un Docker Compose
Tu colles ton compose, tu cherches où mettre le FQDN pour Traefik. Pas d’onglet Domains, pas de champ. La réponse planquée dans la doc : une magic env var, format SERVICE_FQDN_<SERVICE_UPPERCASE>_<PORT> :
SERVICE_FQDN_PLAUSIBLE_8000=https://analytics.example.com
Coolify la détecte et auto-génère les labels Traefik (rule=Host(...), tls.certresolver=letsencrypt). Sans elle, le service tourne mais n’est routé vers rien : déploiement vert qui ne sert rien.
Piège 5 — coolify.serviceName ≠ com.docker.compose.service
Service compose plausible_db (underscore). Ton script filtre sur label=coolify.serviceName=plausible_db → introuvable. Inspect :
com.docker.compose.service: plausible_db # underscore, comme le YAML
coolify.serviceName: plausible-db # tiret, mis par Coolify
Coolify substitue _ → - dans coolify.serviceName. Pour retrouver un container, filtre sur com.docker.compose.service — le label standard Compose qui matche le YAML.
TL;DR
Le fil rouge des 5 : l’UI Coolify ment plus que la base Postgres. User par défaut, validation serveur, labels réels — un SELECT ou un docker inspect te sort du doute plus vite que l’UI.