GiGaRuN Solutions
Vos métiers, nos solutions Excellence IT - La Réunion
+262 692 31 11 91
← Retour aux guides

🚀 Coolify + Astro + Strapi

Déployer un site vitrine statique avec CMS headless éditorial en auto-hébergement

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.

1

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.

2

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.

3

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.

4

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

🔄
Durée totale : ~2 à 3 minutes entre la modification dans Strapi et le site mis à jour en production.
  1. Le gestionnaire de contenu crée ou modifie un item dans Strapi
  2. Le webhook Strapi se déclenche sur l’événement (entry.update, entry.publish...)
  3. Le webhook effectue un GET HTTP vers l’API Coolify avec l’UUID de l’application et &force=true
  4. Coolify lance le build Docker du projet Astro
  5. Astro fetch toutes les collections Strapi via l’API REST
  6. Astro génère le dist/ statique avec les nouvelles données
  7. nginx Alpine est construit avec le nouveau dist/
  8. Coolify remplace l’ancien container
  9. Le site est à jour

2. Comparatif Directus vs Strapi — Quand choisir l’un ou l’autre ?

Ce choix impacte directement l’autonomie de votre client. Le CMS le plus puissant techniquement n’est pas forcément le bon choix pour un gestionnaire de contenu non-technique.

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

A

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
B

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
💡
Bon à savoir : Les deux CMS peuvent coexister sur le même Coolify. Il est possible de conserver Directus pour les démos ou formations tout en utilisant Strapi en production. Astro peut fetch depuis les deux simultanément si besoin — mais une seule source de vérité est recommandée en production.

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.local pointée sur l’IP du VPS (dans /etc/hosts du VPS et de la machine cliente)

4. Déploiement Strapi via Coolify

Ne pas utiliser strapi/strapi:latest — cette image n’existe plus sur Docker Hub. Utiliser le template Coolify natif qui utilise elestio/strapi-production.
1

Créer le projet dans Coolify

Coolify → Projects+ New Project → nommer mon-projet-strapi

2

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.

3

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.

4

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
Durée de vie courte du token admin (30 min). Pour les injections de données, générer un API Token permanent dans Settings → API Tokens.

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"}
      }
    }
  }'
Strapi redémarre automatiquement après chaque création de collection pour appliquer le nouveau schéma. Attendre ~30 secondes avant de créer la collection suivante ou d’injecter des données.

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}}'
Le token admin ne fonctionne pas sur /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

1

Accéder aux API Tokens

Strapi Admin → menu gauche → Settings (tout en bas) → section Global SettingsAPI Tokens

2

Créer le token

+ Create new API Token → Name : astro-build → Token type : Full accessSave

Copier le token immédiatement — il n’est affiché qu’une seule fois.

7. Intégration Astro → Strapi

🚨
Utiliser l’IP interne Docker, pas le nom DNS local. Le build Astro s’exécute dans un container Docker qui ne résout pas le nom DNS local. Utiliser l’IP du container Strapi sur le réseau Coolify.

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 ?? [];
---
Structure de réponse Strapi v5 : 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"
    ]
  }'
Points d’attention :
  • Le champ enabled n’est pas accepté en création — il est activé par défaut
  • headers doit ê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 via GET /api/v1/applications)
  • Site : http://monsite.local