📍 Article principal de la série : Meilisearch 2026 : le guide pratique. Ce tutoriel fait partie du cluster Meilisearch.
Quinze minutes pour passer d’un VPS vide à un Meilisearch de production accessible en HTTPS, prêt à indexer votre catalogue. Ce tutoriel détaille la procédure exacte sur Hetzner CX23 (4,51 €/mois) via Coolify v4, le PaaS open source qui transforme l’auto-hébergement en clic-souris. Méthode validée sur des installations à Dakar, Casablanca, Lagos et Tunis.
Prérequis
- Un VPS Hetzner CX23 ou OVH VPS-1 sous Ubuntu 22.04 LTS / Debian 12.
- Coolify v4 déjà installé (voir Guide Coolify).
- Un nom de domaine avec enregistrement DNS A pointant vers le VPS (par exemple
search.votre-entreprise.com). - Niveau attendu : intermédiaire.
- Temps estimé : 15 à 25 minutes.
Étape 1 — Créer le DNS et propager
Dans votre panel DNS (Cloudflare, OVH, Gandi, Namecheap), créez un enregistrement A : search.votre-entreprise.com → IP de votre VPS. TTL 300 secondes (5 minutes) pour faciliter d’éventuels ajustements. Vérifiez la propagation : dig +short search.votre-entreprise.com. Si Cloudflare est devant, désactivez le proxy (orange cloud → gris) le temps de l’émission Let’s Encrypt.
Étape 2 — Lancer le service Meilisearch dans Coolify
Dans l’interface Coolify : Resources → + New → Service. Recherchez « Meilisearch » dans le catalogue. Le template officiel Coolify déploie la dernière stable (v1.10 au moment de l’écriture) avec un volume persistant pré-configuré.
Nom du service : meilisearch-prod. Serveur : votre Hetzner CX23. Projet : Production (ou créez-le). Cliquez Continue.
Étape 3 — Configurer les variables d’environnement
Sur l’écran de configuration, définissez :
MEILI_ENV=production
MEILI_MASTER_KEY=générez-une-clé-de-32-caractères-minimum
MEILI_DB_PATH=/data/data.ms
MEILI_DUMP_DIR=/data/dumps
MEILI_HTTP_PAYLOAD_SIZE_LIMIT=100MB
MEILI_LOG_LEVEL=INFO
MEILI_NO_ANALYTICS=true
La MEILI_MASTER_KEY est la clé d’admin qui contrôle tout. Générez-la avec :
openssl rand -base64 48 | tr -d '/+=' | head -c 32
Notez-la dans votre coffre Vaultwarden (collection « Infrastructure ») immédiatement. Sans elle, vous perdez le contrôle administratif de l’instance.
Étape 4 — Domaine et HTTPS
Dans l’onglet Domains, saisissez https://search.votre-entreprise.com. Coolify configure son reverse proxy interne (Traefik 2.10) pour gérer le certificat Let’s Encrypt automatiquement. Activez Force HTTPS pour rediriger HTTP → HTTPS.
Le port interne est 7700 par défaut, Coolify le mappe automatiquement au 443 public. Aucune configuration réseau supplémentaire.
Étape 5 — Déployer et vérifier
Cliquez Deploy. Les logs en temps réel montrent : pulling getmeili/meilisearch:v1.10, creating volume, requesting Let’s Encrypt certificate, service healthy. Comptez 60 secondes au premier déploiement.
Test de fonctionnement :
curl https://search.votre-entreprise.com/health
# Retourne : {"status":"available"}
Avec votre master key :
curl -H "Authorization: Bearer VOTRE_MASTER_KEY" \
https://search.votre-entreprise.com/version
# Retourne : {"pkgVersion":"1.10.0","commitSha":"...","commitDate":"..."}
Étape 6 — Créer une API key search-only
Le master key ne doit jamais être utilisé côté front-end. Créez une API key publique avec scope search :
curl -X POST 'https://search.votre-entreprise.com/keys' \
-H 'Authorization: Bearer VOTRE_MASTER_KEY' \
-H 'Content-Type: application/json' \
--data '{
"description": "Frontend search-only key",
"actions": ["search"],
"indexes": ["*"],
"expiresAt": null,
"name": "frontend-public"
}'
La réponse contient "key": "..." — c’est cette clé que vous mettez dans votre code frontend Next.js, Astro ou Vue. Elle ne peut faire que des recherches en lecture, jamais modifier les index.
Étape 7 — Premier index et premier document
curl -X POST 'https://search.votre-entreprise.com/indexes' \
-H 'Authorization: Bearer VOTRE_MASTER_KEY' \
-H 'Content-Type: application/json' \
--data '{ "uid": "products", "primaryKey": "id" }'
curl -X POST 'https://search.votre-entreprise.com/indexes/products/documents' \
-H 'Authorization: Bearer VOTRE_MASTER_KEY' \
-H 'Content-Type: application/json' \
--data '[
{"id":1,"title":"Pagne wax indigo Faso","price":12500,"category":"tissus"},
{"id":2,"title":"Bazin riche Mali","price":18000,"category":"tissus"},
{"id":3,"title":"Sac en cuir Touareg","price":35000,"category":"maroquinerie"}
]'
curl 'https://search.votre-entreprise.com/indexes/products/search' \
-H 'Authorization: Bearer VOTRE_API_KEY_SEARCH' \
-H 'Content-Type: application/json' \
--data '{ "q": "pagne" }'
La réponse retourne le document 1 avec son score de pertinence. Si vous tapez « pagn » ou « pagnee », Meilisearch retourne aussi le document 1 grâce à la typo-tolérance native.
Étape 8 — Configurer les sauvegardes
Cron quotidien sur le VPS pour créer un dump et l’envoyer vers MinIO/B2 :
0 3 * * * curl -X POST -H 'Authorization: Bearer MASTER_KEY' \
https://search.votre-entreprise.com/dumps && \
rclone copy /var/lib/coolify/services/meilisearch-prod/data/dumps \
b2-vaultwarden:meilisearch-backups/$(date +\%F)/
Erreurs fréquentes
| Erreur | Cause | Solution |
|---|---|---|
| 401 Unauthorized partout | Header Authorization mal formé | Vérifier Bearer + clé sans espaces parasites |
| 413 Payload Too Large | Document > 100 Mo | Augmenter MEILI_HTTP_PAYLOAD_SIZE_LIMIT |
| Volume non persistant | Coolify volume mal mappé | Vérifier dans Storages que /data est mappé |
| Latence > 200 ms | RAM saturée | Passer au CCX13 (8 Go) |
| Master key visible dans GitHub | Push sans .env ignoré |
Révoquer la clé, en générer une nouvelle, pusher .gitignore |
| CORS bloque le frontend | Header Access-Control-Allow-Origin manquant |
Configurer Caddy/Traefik pour ajouter les CORS appropriés |
Réalités opérationnelles à Dakar et alentours
Trois ajustements pour les PME africaines. Latence acceptable : 95 ms ping Hetzner Falkenstein depuis Dakar via le câble ACE est bonne pour la recherche e-commerce ; pour de l’autocomplete sur chaque caractère, débouncer côté frontend à 300 ms évite la saturation. Paiement Hetzner : carte Visa émise par CBAO, BICIS ou Société Générale CI fonctionne directement. Wave Business carte virtuelle aussi. Stockage : 25 Go SSD inclus dans le CX23 tiennent largement 5 millions de documents typiques (catalogue produits, articles).
Articles connexes
- Intégrer Meilisearch dans Next.js — la suite logique côté front-end.
- Synchronisation Postgres → Meilisearch via Drizzle ORM
FAQ
Coolify ou docker-compose direct ? Coolify pour 95% des cas (gestion centralisée, HTTPS auto, redémarrages, monitoring). docker-compose direct si vous préférez tout contrôler manuellement et avez moins de 3 services.
Quelle taille pour 1 million de documents ? Hetzner CCX13 (15 €/mois, 8 Go RAM) tient confortablement 1 à 2 millions de documents avec recherches < 50 ms.
Comment monitorer la santé en continu ? Uptime Kuma sur l’endpoint /health toutes les 60 secondes, alerte Telegram ou Discord si réponse différente de {"status":"available"}.
Master key compromise — que faire ? Régénérer la MEILI_MASTER_KEY dans Coolify, redéployer (toutes les sessions sont invalidées), recréer les API keys dérivées, mettre à jour les secrets dans le frontend.
Peut-on migrer un dump entre versions ? Oui, Meilisearch supporte les dumps inter-versions depuis v1.0. Suivre le changelog pour les rares cas de breaking changes.
Pour approfondir
- 🔝 Retour au guide général : guide pratique Meilisearch 2026
- Documentation Meilisearch : meilisearch.com/docs
- Tutoriel suivant : Intégration Next.js
Étape 1 — Provisionner un VPS Hetzner adapté
Pourquoi Hetzner : tarif imbattable pour un moteur de recherche dédié. Le CX22 (2 vCPU, 4 Go RAM, 40 Go SSD) à 4,51 EUR par mois (≈ 2 960 FCFA au taux fixe 1 EUR = 655,957 FCFA) tient confortablement un index Meilisearch jusqu’à 500 000 documents textuels. Au-delà, basculez sur CX32 (8 Go RAM, ≈ 7,55 EUR / 4 950 FCFA).
https://console.hetzner.cloud → Add server
Localisation : Falkenstein (FSN1) — meilleur compromis Europe/Afrique
Image : Ubuntu 24.04 LTS
Type : CX22
Network : IPv4 + IPv6
SSH key : ajouter votre clé publique
Cliquer : Create & Buy now
Sortie de référence : un email Hetzner avec l’IP publique du serveur (ex. 159.69.xxx.xxx) sous 30 secondes. Connectez-vous immédiatement : ssh root@159.69.xxx.xxx. Si la connexion est refusée, vérifiez que la clé SSH a bien été sélectionnée à la création.
Étape 2 — Installer Coolify v4 en une commande
Pourquoi Coolify : alternative auto-hébergée à Heroku/Vercel. On gère Meilisearch, son backup, ses logs et son TLS depuis une interface web, sans toucher aux fichiers Docker à la main.
curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash
Résultat type : à la fin du script (3 à 5 minutes selon la latence Falkenstein → Dakar), l’installeur affiche « Coolify is up and running » avec l’URL http://IP:8000. Ouvrez-la dans un navigateur, créez le compte admin (e-mail + mot de passe long, ≥ 16 caractères). Aucun port supplémentaire à ouvrir manuellement, Coolify gère son firewall.
Étape 3 — Pointer un sous-domaine sur le VPS
Pourquoi un sous-domaine maintenant : Coolify génère un certificat Let’s Encrypt automatiquement à condition que le DNS soit propagé avant le déploiement.
Chez votre registrar (Namecheap, OVH, Gandi, LWS Africa) :
Type : A
Nom : search
Valeur : 159.69.xxx.xxx (IP du VPS)
TTL : 300
Vérification : dig search.votredomaine.com +short
Réponse attendue : 159.69.xxx.xxx
Indicateur de succès : la commande dig retourne l’IP du VPS. Si elle retourne vide ou une autre IP, attendez 5 à 10 minutes (propagation DNS). Pour les domaines en .sn ou .ci gérés par NIC local, comptez parfois 30 minutes.
Étape 4 — Déployer Meilisearch via Coolify
Coolify propose Meilisearch dans son catalogue « Services ». Pas besoin d’écrire un docker-compose.yml.
Coolify → Projects → Add Project → "search-pme"
Resources → New → Service → Meilisearch
Version : v1.11 (LTS, recommandée 2026)
Domain : https://search.votredomaine.com
Environment :
MEILI_ENV=production
MEILI_MASTER_KEY=
MEILI_NO_ANALYTICS=true
Volumes : data (persistant, /meili_data)
Cliquer : Deploy
Pourquoi MEILI_NO_ANALYTICS=true : Meilisearch envoie par défaut des télémétries vers ses serveurs. Pour une PME ouest-africaine soucieuse de la souveraineté de ses données clients, on coupe systématiquement.
Étape 5 — Vérifier l’instance et générer les clés API
Une fois le déploiement terminé (2-3 minutes), Meilisearch répond sur HTTPS. Première vérification de santé :
curl -s https://search.votredomaine.com/health
# Réponse attendue : {"status":"available"}
# Lister les clés générées par Meilisearch
curl -s -H "Authorization: Bearer $MEILI_MASTER_KEY" \
https://search.votredomaine.com/keys | jq .
Sortie attendue : deux clés visibles, « Default Search API Key » (lecture seule) et « Default Admin API Key » (lecture/écriture). Notez l’uid et la key de la clé « Search » : c’est elle que vous exposerez côté frontend, jamais la master.
Étape 6 — Indexer un premier jeu de données
Cas concret : indexer un catalogue produit WooCommerce de 1 200 références (boubous, accessoires, électronique) pour une boutique à Dakar. On exporte au format JSON puis on POST à Meilisearch.
# Format attendu : tableau d'objets avec id unique
cat > produits.json << 'EOF'
[
{"id": 1, "nom": "Boubou bazin riche bleu", "prix": 45000, "categorie": "Femme"},
{"id": 2, "nom": "Sac à main cuir Dakar", "prix": 38500, "categorie": "Accessoires"}
]
EOF
curl -X POST "https://search.votredomaine.com/indexes/produits/documents" \
-H "Authorization: Bearer $ADMIN_KEY" \
-H "Content-Type: application/json" \
--data-binary @produits.json
Validation visuelle : la réponse contient {"taskUid": N, "status": "enqueued"}. Quelques secondes plus tard, GET /indexes/produits/stats renvoie numberOfDocuments: 2. Sur 1 200 produits, l’indexation prend moins de 5 secondes sur le CX22.
Étape 7 — Configurer la pertinence (filtres et tri)
Pourquoi cette étape : par défaut, Meilisearch recherche dans tous les champs avec le même poids. Pour une boutique, le nom doit primer sur la description, et on doit pouvoir filtrer par catégorie ou prix.
curl -X PATCH "https://search.votredomaine.com/indexes/produits/settings" \
-H "Authorization: Bearer $ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"searchableAttributes": ["nom", "categorie", "description"],
"filterableAttributes": ["categorie", "prix"],
"sortableAttributes": ["prix"],
"rankingRules": ["words","typo","proximity","attribute","sort","exactness"]
}'
Sortie attendue : un taskUid et un statut « enqueued » puis « succeeded » en moins de 2 secondes. Dès que la tâche est terminée, vous pouvez filtrer : ?q=bazin&filter=prix > 30000 AND categorie="Femme".
Étape 8 — Intégrer Meilisearch côté frontend
Côté navigateur, on utilise meilisearch-js (≈ 25 Ko gzippé, sans dépendance lourde). On expose UNIQUEMENT la clé « Search » en lecture seule.
import { MeiliSearch } from "meilisearch";
const client = new MeiliSearch({
host: "https://search.votredomaine.com",
apiKey: "VOTRE_SEARCH_KEY_PUBLIC"
});
const input = document.querySelector("#search");
input.addEventListener("input", async e => {
const r = await client.index("produits").search(e.target.value, { limit: 10 });
document.querySelector("#results").innerHTML = r.hits
.map(h => `<li>${h.nom} — ${h.prix.toLocaleString("fr-FR")} FCFA</li>`)
.join("");
});
Indicateur de succès : taper « boubou » affiche les produits correspondants en moins de 50 ms (latence réseau Dakar → Falkenstein typique : 60-90 ms, donc ressenti utilisateur ≈ 100 ms total). Pour creuser ce sujet, voyez le guide moteur de recherche principal et le tutoriel Meilisearch Hetzner Coolify qui détaille la sauvegarde S3 compatible (Backblaze B2, Wasabi).
Étape 9 — Sauvegarder l’index et superviser
Pourquoi cette étape n’est pas optionnelle : un VPS peut redémarrer, un volume peut être corrompu. Une sauvegarde quotidienne du dump Meilisearch est la dernière ligne de défense.
# Créer un dump (snapshot binaire)
curl -X POST "https://search.votredomaine.com/dumps" \
-H "Authorization: Bearer $ADMIN_KEY"
# Réponse : {"taskUid":N,"status":"enqueued"}
# Récupérer le dump généré
ls -lh /var/lib/docker/volumes/*meili*/_data/dumps/
# Copier vers Backblaze B2 (~ 0,005 USD/Go/mois)
rclone copy /chemin/dump.dump b2-pme:meili-backups/
Ce que vous devez voir : un fichier .dump de 50 à 300 Mo selon le catalogue. Programmez un cron quotidien à 02h00 UTC. En cas de perte, restaurez avec --import-dump /chemin/du/dump.dump au démarrage du conteneur. Côté supervision, Coolify affiche déjà CPU/RAM en temps réel — alerte recommandée à 80 % de RAM pendant plus de 5 minutes.
Étape 10 — Mesurer les performances et ajuster
Pourquoi mesurer maintenant : avant d’ouvrir le moteur à 1 000 utilisateurs simultanés, il faut connaître la limite réelle de votre instance. Un test de charge basique avec hey donne une réponse en 5 minutes.
apt install -y hey
# 500 requêtes, 50 en parallèle
hey -n 500 -c 50 \
-H "Authorization: Bearer $SEARCH_KEY" \
"https://search.votredomaine.com/indexes/produits/search?q=boubou"
Résultat type sur CX22 avec 1 200 documents : médiane < 30 ms, 99e percentile < 80 ms, 0 erreur. Si le 99e percentile dépasse 200 ms, c’est le moment de passer en CX32 ou de réduire le nombre de searchableAttributes. Surveillez la RAM avec docker stats meilisearch pendant le test : au-dessus de 85 % d’utilisation soutenue, l’OOM killer Linux peut tuer le processus.