Ce dossier contient tout ce qui s'installe côté application cliente pour se brancher sur CONTROL. Un sous-dossier par module :
inocampagne/
inodesk/
inoshop/
inotrack/
inowatch/
inobackup.sh
laravel-control-backup/
Les trois scripts embarquables (inotrack.js, inodesk.js, inocampagne.js) partagent le même transport (clé publique dans l'URL, corps text/plain, aucun préflight) et le même format d'erreur. Un intégrateur qui en a branché un connaît déjà les autres.
inotrack.js
inodesk.js
inocampagne.js
text/plain
Ce qu'il faut installer côté application cliente pour déposer ses sauvegardes de base de données sur CONTROL.
control:backup
Le principe est toujours le même : dump → gzip → sha256 → POST authentifié. CONTROL écrit la sauvegarde d'abord sur son propre disque, puis la réplique sur un stockage objet hors-site, applique la rétention GFS et alerte par email si une sauvegarde attendue n'arrive pas.
En plus de la base, les deux intégrations savent archiver des chemins de fichiers (uploads, .env, dossiers de configuration…) : voir la section 6.
.env
INOBACKUP › Applications › Nouvelle application :
Planification : fréquence, heure et fuseau (Africa/Lome par défaut) — c'est ce créneau qui déclenche l'alerte « sauvegarde manquante » s'il n'est pas honoré ;
Africa/Lome
INOBACKUP › Clés API › Nouvelle clé : choisissez l'application, nommez la clé (ex. « Cron VPS production »). La clé CTRLBK_… n'est affichée qu'une seule fois : copiez-la immédiatement. Elle n'est stockée que sous forme d'empreinte : perdue, elle se révoque et se recrée, elle ne se retrouve pas.
CTRLBK_…
Notez l'URL de dépôt : https://plateforme.inovertix.com/api/inobackup.
https://plateforme.inovertix.com/api/inobackup
/ping
Avant d'automatiser quoi que ce soit, vérifiez que la clé fonctionne :
curl -sS https://plateforme.inovertix.com/api/inobackup/ping \ -H "Authorization: Bearer CTRLBK_votre_cle"
Réponse attendue (HTTP 200) :
{ "application": { "name": "Boutique en ligne", "slug": "boutique-en-ligne", "frequency": "daily", "timezone": "Africa/Lome", "last_backup_at": null }, "server_time": "2026-08-11T09:12:44+00:00", "max_size_mb": 2048 }
401
403
429
L'appel met à jour « Dernière utilisation » dans CONTROL : l'encart Intégration de la fiche application affiche alors « Intégration active ».
# 1. Le script sudo curl -o /usr/local/bin/inobackup.sh \ https://raw.githubusercontent.com/INOVERTIX/CONTROL/main/integrations/inobackup.sh sudo chmod 700 /usr/local/bin/inobackup.sh # 2. La configuration (mode 600 : la clé est un secret) sudo tee /etc/inobackup.env > /dev/null <<'EOF' DB_HOST=127.0.0.1 DB_PORT=3306 DB_USER=monapp DB_PASS=motdepasse # Une ou plusieurs bases, séparées par des espaces. Chacune est déposée séparément # et garde SA PROPRE rotation côté CONTROL (voir « Plusieurs bases » ci-dessous). DB_NAMES=monapp_prod INOBACKUP_URL=https://plateforme.inovertix.com/api/inobackup INOBACKUP_KEY=CTRLBK_votre_cle EOF sudo chmod 600 /etc/inobackup.env # 3. Essai à blanc sudo /usr/local/bin/inobackup.sh # 4. Cron quotidien à 02h00 (heure du serveur — alignez-la sur CONTROL) echo '0 2 * * * root /usr/local/bin/inobackup.sh >> /var/log/inobackup.log 2>&1' \ | sudo tee /etc/cron.d/inobackup
docker exec
Sur Dokploy, la base tourne généralement dans un conteneur et mysqldump n'existe pas sur l'hôte. Renseignez simplement le nom du conteneur : le script utilise alors le client du conteneur.
mysqldump
docker ps --format '{{.Names}}' # repérer le nom exact du conteneur de base # dans /etc/inobackup.env : DOCKER_CONTAINER=monapp-db-1 DB_USER=monapp DB_PASS=motdepasse DB_NAMES=monapp_prod
DB_HOST/DB_PORT deviennent inutiles : la commande s'exécute à l'intérieur du conteneur. Le mot de passe est transmis via MYSQL_PWD (jamais visible dans ps).
DB_HOST
DB_PORT
MYSQL_PWD
ps
Un même serveur héberge souvent plusieurs bases. Listez-les dans DB_NAMES : le script les traite l'une après l'autre et envoie chacune avec son propre db_name.
DB_NAMES
db_name
DB_NAMES="client_crm client_blog client_shop"
Conséquences à connaître :
Volume : chaque base conserve son propre cycle. Quinze bases en 7 j / 4 sem. / 3 mois plafonnent à ~210 fichiers, contre 14 pour une base seule.
Supervision : une base qui cesse de déposer déclenche une alerte en la nommant, même si les quatorze autres sont bien arrivées.
Une base en échec n'interrompt pas les suivantes. Le script traite toute la liste, puis sort en erreur avec le récapitulatif — surveillez le code de sortie du cron, pas seulement la présence de nouveaux fichiers.
Archives de fichiers : elles forment leur propre série (BACKUP_FILES_LABEL, fichiers par défaut). Ne leur donnez pas le nom d'une base.
BACKUP_FILES_LABEL
fichiers
Si les bases vont et viennent, DB_DISCOVER=1 (avec DB_NAMES vide) les découvre via SHOW DATABASES en excluant les bases système. Pratique, mais la liste explicite reste préférable : elle rend visible l'oubli d'une base au lieu de le masquer.
DB_DISCOVER=1
SHOW DATABASES
mysqldump est disponible sur la plupart des offres mutualisées, mais l'accès SSH ne l'est pas toujours. Deux étapes :
Déposer le script (Gestionnaire de fichiers) dans un dossier hors public_html, par exemple /home/utilisateur/scripts/inobackup.sh, puis lui donner les droits 700.
public_html
/home/utilisateur/scripts/inobackup.sh
700
Renseigner la configuration directement en tête du script (l'entête CONFIGURATION) plutôt que via /etc/inobackup.env, auquel vous n'avez pas accès :
CONFIGURATION
/etc/inobackup.env
DB_HOST="localhost" DB_USER="utilisateur_monapp" DB_PASS="motdepasse" DB_NAMES="utilisateur_monapp" INOBACKUP_URL="https://plateforme.inovertix.com/api/inobackup" INOBACKUP_KEY="CTRLBK_votre_cle" TMP_DIR="/home/utilisateur/tmp"
Créer la tâche cron dans cPanel › Tâches Cron :
0 2 * * * /bin/bash /home/utilisateur/scripts/inobackup.sh >> /home/utilisateur/logs/inobackup.log 2>&1
Renseignez une adresse dans « Adresse e-mail » pour recevoir la sortie en cas d'erreur.
Espace disque : le dump compressé est écrit dans TMP_DIR avant l'envoi puis supprimé. Prévoyez la place correspondante dans votre quota.
TMP_DIR
Pour une application Laravel, préférez le package : il lit la connexion de l'application elle-même, journalise dans laravel.log et s'enregistre dans le scheduler existant.
laravel.log
composer config repositories.control-backup path ../CONTROL/integrations/laravel-control-backup composer require inovertix/control-backup:@dev php artisan vendor:publish --tag=control-backup-config # .env : # CONTROL_BACKUP_URL=https://plateforme.inovertix.com/api/inobackup # CONTROL_BACKUP_KEY=CTRLBK_votre_cle php artisan control:backup
Puis, dans routes/console.php :
routes/console.php
Schedule::command('control:backup')->dailyAt('02:00')->withoutOverlapping();
Détails complets : laravel-control-backup/README.md.
laravel-control-backup/README.md
Une sauvegarde de base ne suffit presque jamais : les fichiers téléversés par les utilisateurs (uploads/, media/) et les fichiers de configuration (.env) ne sont pas dans la base et ne se régénèrent pas.
uploads/
media/
# dans /etc/inobackup.env (ou en tête du script) BACKUP_PATHS="/home/monapp/public_html/uploads /home/monapp/public_html/.env"
Le script produit alors deux dépôts par exécution : le dump SQL (nature base de données) puis une archive .tar.gz des chemins (nature fichiers). Les deux suivent la même politique de double stockage et de rétention.
.tar.gz
CONTROL_BACKUP_PATHS=/var/www/monapp/storage/app/public,/var/www/monapp/.env
(séparés par des virgules ; la liste vide désactive l'archive de fichiers)
Par défaut : node_modules, .git, vendor, *.log.
node_modules
.git
vendor
*.log
Un chemin listé mais inexistant est signalé sur stderr et ignoré ; la sauvegarde continue. Si aucun des chemins n'existe, l'archive est abandonnée en erreur.
stderr
À savoir sur la supervision : CONTROL considère aujourd'hui une application « à jour » dès qu'une sauvegarde — de n'importe quelle nature — est arrivée dans le créneau. Si vos fichiers cessent d'être envoyés alors que la base continue, l'application restera au vert. Filtrez la liste sur la nature « Fichiers » pour le vérifier.
POST /api/inobackup/upload
multipart/form-data
file
.sql
.sql.gz
.gz
.zip
checksum
kind
database
files
note
Réponse 201 :
201
{ "id": "01J...", "stored_filename": "b1f0…-….sql.gz", "size_bytes": 4831201, "checksum_sha256": "9f86d0…", "local_status": "stored", "s3_status": "pending" }
s3_status: "pending" est normal : la copie vers le stockage hors-site est asynchrone (3 tentatives avec backoff, puis alerte email en cas d'échec définitif).
s3_status: "pending"
413
422
GET /api/inobackup/ping
Voir la section 2.
401 invalid_api_key
403 application_inactive
413 file_too_large
422 corrupt_archive
gzip -t
422 checksum_mismatch
s3_status
pending