Aller au contenu
Sylvain Joffraud l4w
Retour

Coolify webhook : un push, cinq déploiements

Un webhook Coolify manuel ne vise pas une application : il vise toutes les applications dont l’URL de dépôt contient <owner>/<repo> sur la branche poussée. Sur mon instance Coolify 4.0.0 (état relevé le 4 août 2026 sur srv-a), un seul push Gitea sur le dépôt du site vitrine déclenche cinq déploiements, parce que cinq applications partagent ce dépôt et cette branche. Et quand un webhook ne déclenche rien, Coolify répond quand même HTTP 200 : la raison est écrite dans le corps de la réponse, jamais dans le code de statut.

Trois chemins de déploiement qui ne partagent rien

Coolify propose trois manières de lancer un déploiement depuis l’extérieur. Elles n’ont ni la même route, ni le même secret, ni la même logique pour retrouver l’application :

MécanismeRouteSecret vérifiéMatching de l’application
GitHub AppPOST /webhooks/source/github/eventssecret de l’App, globalrepository_project_id + source non publique
Webhook manuelPOST /webhooks/source/{github,gitea,gitlab,bitbucket}/events/manualsecret par applicationgit_repository LIKE %owner/repo% + git_branch
API deployGET ou POST /api/v1/deploy?uuid=…token API (permission deploy)UUID explicite

Mes dépôts Gitea sont joignables seulement par le mesh WireGuard, donc en deploy key, comme expliqué dans l’article sur Coolify et un Gitea en IP privée. Pour eux, c’est le webhook manuel, créé à la main dans Gitea avec l’URL et le secret affichés dans l’onglet Webhooks de l’application.

Pourquoi un webhook Coolify déclenche plusieurs déploiements ?

Le site vitrine est un seul dépôt, perso/vitrine, d’où sortent cinq vhosts : le site, deux sous-sites et deux redirections. Cinq applications Coolify, même dépôt, même branche main. Le webhook manuel cherche les applications avec un LIKE : les cinq correspondent, les cinq partent en déploiement.

Ici, c’est voulu. Mais le LIKE n’est pas ancré : %perso/vitrine% correspond aussi à perso/vitrine-admin. Un push sur vitrine déploie donc aussi les applications construites depuis vitrine-admin sur la même branche.

Un webhook manuel Coolify déploie toutes les applications dont l’URL de dépôt contient owner/repo sur la branche poussée, pas seulement celle qui a fourni l’URL du webhook.

Deuxième conséquence : le secret manuel est par application, pas par dépôt. Un webhook Gitea ne porte qu’un secret, alors que les cinq applications en ont chacune un, généré automatiquement. Il faut soit créer un webhook Gitea par application, soit aligner les cinq secrets sur la même valeur. Je l’ai noté comme point à vérifier au prochain déploiement partiel sur ce dépôt.

HTTP 200 ne veut pas dire « déployé »

Ma première fausse piste quand un push ne déclenche rien : l’interrupteur Auto Deploy. Actif par défaut, il l’était sur mes 12 applications. Les contrôleurs de webhook répondent 200 avec un message explicite : il faut lire le corps dans Recent Deliveries (GitHub) ou dans l’historique du webhook (Gitea).

Corps de la réponse (HTTP 200)Cause
Nothing to do. No GitHub App found.l’en-tête X-GitHub-Hook-Installation-Target-Id ne correspond à aucune App connue
Invalid signature.secret différent entre la forge et Coolify
Nothing to do. No applications found with branch 'X'.la branche de l’application n’est pas celle poussée
Webhook secret not configured.secret manuel vide sur l’application
Deployments disabled.Auto Deploy désactivé
Changed files do not match watch paths.watch_paths défini et aucun fichier modifié ne correspond

Un test « Test Delivery » réussi dans Gitea renvoie {"status":"success","message":"Deployment queued.", …}.

Les deux cas où rien n’arrive, sans aucun message

La source « Public GitHub » ne reçoit jamais de webhook. Le handler de la GitHub App filtre avec whereRelation('source', 'is_public', false). Une application créée en Public Repository n’est jamais auto-déployée par l’App : il faut la rattacher à la GitHub App ou lui poser un webhook manuel.

Un repository_project_id vide rend l’application invisible à la GitHub App. repository_project_id est l’identifiant numérique du dépôt chez GitHub. Coolify ne le renseigne que si on choisit le dépôt dans la liste déroulante de la source, pas en collant une URL. À NULL, l’App ne trouve jamais l’application, et aucun message ne le signale.

La requête SQL qui répond avant l’UI

Pour voir en une fois dépôt, branche, identifiant GitHub et flag d’auto-deploy de toutes les applications :

ssh deploy@srv-a 'docker exec coolify-db psql -U coolify -d coolify -c \
  "SELECT a.name, a.git_repository, a.git_branch, a.repository_project_id, s.is_auto_deploy_enabled \
   FROM applications a JOIN application_settings s ON s.application_id = a.id ORDER BY a.id;"'

Deux applications avec le même couple dépôt/branche partiront ensemble. Une application GitHub App avec repository_project_id vide ne partira jamais.

Lessons learned

Questions fréquentes

Pourquoi un webhook Coolify déclenche-t-il le déploiement de plusieurs applications ?
Le webhook manuel de Coolify 4.0.0 cherche les applications avec git_repository LIKE %owner/repo% et la même branche. Toutes les applications construites depuis ce dépôt et cette branche sont donc déployées. Le LIKE n’est pas ancré : un dépôt vitrine matche aussi vitrine-admin. Éviter les noms de dépôts qui sont préfixes l’un de l’autre.
Le webhook Coolify répond 200 mais rien ne se déploie, que faut-il regarder ?
Coolify renvoie HTTP 200 même quand il ne déploie rien : la raison est dans le corps de la réponse. Les messages courants sont Invalid signature. (secret divergent), Nothing to do. No GitHub App found. (mauvaise App) ou Changed files do not match watch paths.. Il faut lire le corps dans « Recent Deliveries » côté GitHub ou dans l’historique du webhook côté Gitea.
Pourquoi une application Coolify en « Public Repository » ne s’auto-déploie-t-elle jamais ?
Le handler du webhook GitHub App de Coolify filtre les applications avec whereRelation('source', 'is_public', false). Une application créée depuis la source « Public GitHub » est donc ignorée, quel que soit son réglage Auto Deploy. Deux solutions : la rattacher à la GitHub App de l’instance, ou lui poser un webhook manuel avec son propre secret.
Le paramètre allowed_ips de Coolify bloque-t-il les webhooks ?
Non. Dans Coolify 4.0.0, allowed_ips ne filtre que les routes de l’API (/api/v1/…), dont /api/v1/deploy. Les routes /webhooks/* sont hors de ce groupe : leur seule protection est la signature HMAC SHA-256 calculée avec le secret. Il ne faut donc jamais vider un secret de webhook « pour tester ».

Partager cet article :

Article précédent
RLS Postgres : `INSERT … RETURNING` refusé en 403
Article suivant
Gemma 4 sous MLX : le cache à fenêtre glissante se relit