📚 Table des matières
- 1. Vue d’ensemble de la stack
- 2. Comparatif Directus vs Strapi — Quand choisir l’un ou l’autre ?
- 3. Prérequis
- 4. Déploiement Strapi via Coolify
- 5. Création des collections via l’API
- 6. Générer un API Token Strapi
- 7. Intégration Astro → Strapi
- 8. Webhook Strapi → rebuild Coolify automatique
- 9. Problèmes rencontrés et solutions
- 10. Résumé des commandes utiles
1. Vue d’ensemble de la stack
Cette stack assemble quatre composants pour produire un site vitrine statique performant, gérable par un non-développeur via un éditeur de contenu moderne, et déployé automatiquement à chaque modification.
Coolify — PaaS self-hosted
Orchestre Docker, Traefik (reverse proxy) et les déploiements via une interface web. Prend en charge le build des images, le routing des domaines, les certificats SSL et les webhooks de déclenchement. Équivalent self-hosted de Railway ou Render.
Astro — Static Site Generator (SSG)
En mode output: 'static', Astro génère du HTML/CSS/JS statique. Il fetch l’API Strapi au build time — pas au runtime. Le site final est complètement statique, sans dépendance vers Strapi en production.
Strapi — Headless CMS éditorial
CMS headless qui expose une API REST et GraphQL. L’interface d’administration offre un éditeur WYSIWYG avec insertion d’images inline, une médiathèque intégrée et un Content-Type Builder visuel. Les webhooks natifs de Strapi déclenchent le rebuild Coolify à chaque modification de contenu.
nginx — Serveur de fichiers statiques
Le dist/ généré par Astro est servi via nginx Alpine. Aucun Node.js en production — image finale légère (~25 Mo), performante et sécurisée.
Cycle complet de mise à jour
- Le gestionnaire de contenu crée ou modifie un item dans Strapi
- Le webhook Strapi se déclenche sur l’événement (
entry.update,entry.publish...) - Le webhook effectue un GET HTTP vers l’API Coolify avec l’UUID de l’application et
&force=true - Coolify lance le build Docker du projet Astro
- Astro fetch toutes les collections Strapi via l’API REST
- Astro génère le
dist/statique avec les nouvelles données - nginx Alpine est construit avec le nouveau
dist/ - Coolify remplace l’ancien container
- Le site est à jour
2. Comparatif Directus vs Strapi — Quand choisir l’un ou l’autre ?
Tableau comparatif détaillé
| Critère | Directus | Strapi |
|---|---|---|
| Éditeur de contenu | ⚠ Champs structurés, pas de WYSIWYG par défaut | ✅ WYSIWYG natif (Tiptap/CKEditor) |
| Insertion d’images inline | ❌ Non natif — image = champ séparé | ✅ Oui, via médiathèque dans l’éditeur |
| Médiathèque | ⚠ Existe mais déconnectée de l’édition | ✅ Intégrée, upload drag&drop, recadrage |
| Contenu éditorial (articles, blogs) | ❌ Laborieux — pas fait pour ça | ✅ Usage principal de l’outil |
| Données structurées (tarifs, services) | ✅ Excellent — logique BDD native | ✅ Bon — Content-Type Builder visuel |
| UX pour non-technique | ❌ Interface type backoffice ERP, déroutante | ✅ Plus accessible, terminologie CMS classique |
| Automatisation / Flows | ✅ Flows visuels puissants (nodes à connecter) | ⚠ Webhooks simples uniquement |
| Webhooks natifs | ⚠ Via Flows (configuration complexe) | ✅ Natifs, simples à configurer |
| Démarrage Docker | ✅ Rapide (<30 secondes) | ⚠ Lent (3–5 min, compile l’admin au 1er start) |
| Consommation ressources | ✅ Léger | ⚠ Plus lourd (Node.js + build admin) |
| API REST / GraphQL | ✅ Complet, bien documenté | ✅ Complet, bien documenté |
| Permissions et rôles | ✅ Très granulaire | ✅ Très granulaire |
| Intégration Astro | ✅ Identique — simple fetch REST | ✅ Identique — simple fetch REST |
| Template Coolify | ✅ Oui | ✅ Oui (image elestio/strapi-production) |
| Origine | Pays-Bas | France (Paris) 🇫🇷 |
Règle de décision
Choisir Strapi RECOMMANDÉ pour les sites vitrine
- Le site doit publier du contenu éditorial (articles de blog, pages de service rédigées, guides, actualités)
- Le gestionnaire de contenu est non-technique et doit pouvoir travailler en autonomie
- Les contenus incluent des images inline dans des textes (pas juste des images de couverture)
- Vous voulez livrer un CMS simple et former rapidement votre client
- Le site doit évoluer vers un blog ou une base de ressources
Choisir Directus
- Le site n’a que des données structurées — tarifs, listes de services, équipe (pas d’articles)
- Le gestionnaire est un développeur ou un profil technique (à l’aise avec une interface type backoffice ERP)
- Vous avez besoin d’automatisations complexes via les Flows (logique conditionnelle, chaînes d’actions)
- Vous construisez une interface d’administration sur-mesure qui consomme l’API Directus
- Vous faites une démo technique ou une formation sur les CMS headless orientés BDD
3. Prérequis
- Coolify installé et opérationnel (voir guide Coolify + Astro + Directus)
- Accès SSH au VPS Coolify
- Repo GitHub du site Astro existant
- Entrée DNS locale pour
strapi.monsite.localpointée sur l’IP du VPS (dans/etc/hostsdu VPS et de la machine cliente)
4. Déploiement Strapi via Coolify
strapi/strapi:latest — cette image n’existe plus sur Docker Hub. Utiliser le template Coolify natif qui utilise elestio/strapi-production.Créer le projet dans Coolify
Coolify → Projects → + New Project → nommer mon-projet-strapi
Ajouter Strapi via le template
Dans le projet → + New Resource → rechercher Strapi dans les templates → sélectionner → Deploy
Attention : Le premier démarrage prend 3–5 minutes. Strapi compile l’interface d’administration React au premier boot. Ne pas interrompre.
Configurer le domaine local
Dans la ressource Strapi → Configuration → champ Domains → remplacer l’URL sslip.io générée par : http://strapi.monsite.local
Sur le VPS :
sudo bash -c 'echo "127.0.0.1 strapi.monsite.local" >> /etc/hosts'
Sur la machine cliente (Windows, en admin) :
echo [IP_VPS] strapi.monsite.local >> C:\Windows\System32\drivers\etc\hosts
Puis Redeploy (Stop + Deploy) pour appliquer le nouveau domaine dans Traefik.
Créer le compte admin
Accéder à http://strapi.monsite.local/admin → premier accès = création du compte administrateur.
5. Création des collections via l’API
Les collections peuvent être créées via l’API admin Strapi (token JWT) ou via l’interface Content-Type Builder. Voici la méthode API :
Authentification admin
curl -X POST http://strapi.monsite.local/admin/login \
-H 'Content-Type: application/json' \
-d '{"email":"admin@example.com","password":"motdepasse"}'
# Récupérer le token dans data.token
Création d’une collection (exemple : Service)
curl -X POST http://strapi.monsite.local/content-type-builder/content-types \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer [TOKEN_ADMIN]' \
-d '{
"contentType": {
"displayName": "Service",
"singularName": "service",
"pluralName": "services",
"kind": "collectionType",
"attributes": {
"titre": {"type": "string", "required": true},
"description": {"type": "text"},
"ordre": {"type": "integer"}
}
}
}'
Injection de données (avec API Token)
curl -X POST http://strapi.monsite.local/api/services \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer [API_TOKEN]' \
-d '{"data": {"titre": "Infogérance IT", "description": "...", "ordre": 1}}'
/api/. Les endpoints publics nécessitent un API Token généré dans Settings → API Tokens (type Full access).6. Générer un API Token Strapi
Accéder aux API Tokens
Strapi Admin → menu gauche → Settings (tout en bas) → section Global Settings → API Tokens
Créer le token
+ Create new API Token → Name : astro-build → Token type : Full access → Save
Copier le token immédiatement — il n’est affiché qu’une seule fois.
7. Intégration Astro → Strapi
Récupérer l’IP interne de Strapi
sudo docker inspect [NOM_CONTAINER_STRAPI] | grep '"IPAddress"'
# Ex : [IP_INTERNE_STRAPI]
Code Astro — fetch depuis Strapi
---
const STRAPI = 'http://[IP_INTERNE_STRAPI]:1337';
const STRAPI_TOKEN = 'votre_api_token_ici';
const headers = { 'Authorization': `Bearer ${STRAPI_TOKEN}` };
const [servicesRes, tarifsRes] = await Promise.all([
fetch(`${STRAPI}/api/services?sort=ordre&pagination[limit]=100`, { headers }),
fetch(`${STRAPI}/api/tarifs?sort=ordre&pagination[limit]=100`, { headers }),
]);
const services = (await servicesRes.json()).data ?? [];
const tarifs = (await tarifsRes.json()).data ?? [];
---
data est un tableau d’objets avec les champs directement à la racine (pas de sous-objet attributes comme en v4). Ex : item.titre et non item.attributes.titre.8. Webhook Strapi → rebuild Coolify automatique
Configuration via l’API admin Strapi. Récupérer d’abord un token admin frais, puis :
curl -X POST http://strapi.monsite.local/admin/webhooks \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer [TOKEN_ADMIN]' \
-d '{
"name": "coolify-rebuild",
"url": "http://[IP_VPS]:8001/api/v1/deploy?uuid=[UUID_APP]&force=true",
"headers": {
"Authorization": "Bearer [TOKEN_API_COOLIFY]"
},
"events": [
"entry.create",
"entry.update",
"entry.delete",
"entry.publish",
"entry.unpublish"
]
}'
- Le champ
enabledn’est pas accepté en création — il est activé par défaut headersdoit être un objet clé/valeur, pas un tableau- L’UUID de l’application Coolify est récupérable via
GET /api/v1/applications
9. Problèmes rencontrés et solutions
| Problème | Cause | Solution |
|---|---|---|
pull access denied for strapi/strapi |
Image officielle supprimée de Docker Hub | Utiliser le template Coolify natif (image elestio/strapi-production) |
| 404 sur le domaine local configuré | Coolify utilise encore l’ancien domaine sslip.io dans les labels Traefik |
Changer le domaine dans Configuration → Save → puis Stop + Deploy (pas juste Restart) |
getaddrinfo ENOTFOUND strapi.monsite.local au build |
Le container de build Docker ne résout pas le DNS local | Remplacer le hostname par l’IP interne Docker du container Strapi (ex: 172.20.x.x:1337) |
401 Unauthorized sur /api/ avec token admin |
Le token JWT admin ne fonctionne que sur les endpoints /admin/ |
Générer un API Token dans Settings → API Tokens pour les endpoints /api/ |
| 400 Bad Request “unspecified keys: enabled” sur création webhook | Le champ enabled n’est pas accepté à la création |
Retirer enabled du payload — activé par défaut |
| Strapi met 3–5 min à démarrer | Compilation de l’interface React au premier boot | Normal. Attendre que le container soit healthy avant d’accéder à l’admin |
URL sslip.io redirige vers un autre VPS |
L’IP publique du VPS local est partagée avec d’autres machines de l’infrastructure | Toujours utiliser un domaine .local en développement. Ne jamais exposer un service interne via sslip.io en multi-VPS |
10. Résumé des commandes utiles
Vérifier l’IP interne du container Strapi
sudo docker inspect $(sudo docker ps | grep strapi | grep -v postgres | awk '{print $1}') \
| python3 -c "import sys,json; nets=json.load(sys.stdin)[0]['NetworkSettings']['Networks']; \
[print(k, v['IPAddress']) for k,v in nets.items()]"
Forcer un rebuild via l’API Coolify
curl -X GET 'http://[IP_VPS]:8001/api/v1/deploy?uuid=[UUID_APP]&force=true' \
-H 'Authorization: Bearer [TOKEN_COOLIFY]'
Lister les webhooks Strapi
curl http://strapi.monsite.local/admin/webhooks \
-H 'Authorization: Bearer [TOKEN_ADMIN]'
Exemple de références à adapter
- Coolify dev :
http://[IP_VPS]:8001— user SSH :[USER] - Strapi admin :
http://strapi.monsite.local/admin - IP interne Strapi :
[IP_INTERNE_STRAPI]:1337(à vérifier après restart) - UUID app :
[UUID_APP](récupérable viaGET /api/v1/applications) - Site :
http://monsite.local