ORBITE · Application réelle

Guide de déploiement

Installer, vérifier, sauvegarder, mettre à jour et restaurer ORBITE sur un VPS avec Docker et Traefik.

Ce que couvre ce guide

Ce guide concerne l'application réelle livrée dans orbite-app.zip : un serveur Django, une base PostgreSQL et une seule adresse web pour les trois profils. Les fichiers de maquettes (orbite-ba.html, orbite-superviseur.html, orbite-console-manager.html) ne se déploient pas : ils servent aux démonstrations.

ConteneurRôle
dbBase PostgreSQL 16, volume orbite_db
webApplication, derrière Traefik en HTTPS ; photos dans orbite_media, sauvegardes dans orbite_backups
schedulerTâches planifiées : escalades et contre-visites toutes les 5 minutes ; sauvegarde, test de restauration et purge chaque nuit
HTTPS est obligatoire. Sans certificat valide, les navigateurs bloquent la géolocalisation et la caméra : aucune visite n'est possible.

Prérequis

  • Un VPS Linux avec Docker et Docker Compose (commande docker compose).
  • Un Traefik déjà en service sur ce VPS, relié à un réseau Docker externe, avec un résolveur de certificats Let's Encrypt.
  • Un sous-domaine (par exemple orbite.tstdigitalproducts.com) dont l'enregistrement DNS de type A pointe vers l'adresse IP du VPS.
  • L'archive orbite-app.zip. Elle ne contient ni fichier .env, ni base, ni photos.
  • Un coffre-fort ou un gestionnaire de mots de passe, hors du serveur, pour garder les clés de chiffrement.

Installer

  1. Copier l'archive sur le VPS, depuis le PC Windows (PowerShell) :
    scp .\orbite-app.zip root@<ip-du-vps>:/opt/
  2. Décompresser sur le VPS :
    ssh root@<ip-du-vps>
    cd /opt && unzip orbite-app.zip && cd orbite-app

    Si unzip manque : apt install -y unzip.

  3. Préparer le fichier de configuration :
    cp .env.example .env
    openssl rand -base64 48      # à coller dans ORBITE_SECRET_KEY
    openssl rand -base64 32      # à coller dans ORBITE_MEDIA_KEY
    openssl rand -base64 32      # à coller dans ORBITE_BACKUP_KEY (clé différente)
    nano .env

    Le détail de chaque variable est dans la section suivante.

  4. Trouver le nom du réseau Traefik et le reporter dans TRAEFIK_NETWORK :
    docker network ls
  5. Construire et démarrer :
    docker compose up -d --build
    docker compose ps

    db, web et scheduler doivent apparaître « healthy » ou « running ». La base est créée et mise à niveau au démarrage.

  6. Créer le premier manager : voir la section dédiée.

Le fichier .env

Sans les valeurs obligatoires, l'application refuse de démarrer. Ce fichier ne se partage pas et ne se versionne jamais.

VariableContenu
ORBITE_DOMAINLe sous-domaine, sans https : orbite.tstdigitalproducts.com
ORBITE_HOSTSLe même nom (plusieurs noms séparés par des virgules)
ORBITE_CSRF_ORIGINSL'adresse complète avec https : https://orbite.tstdigitalproducts.com
ORBITE_DEBUG0 en production, toujours
ORBITE_SECRET_KEYClé Django, 40 caractères au moins
ORBITE_MEDIA_KEYChiffrement des photos et selfies au repos
ORBITE_BACKUP_KEYChiffrement des sauvegardes, différente de la précédente
ORBITE_DB_PASSWORDMot de passe PostgreSQL, long et aléatoire
TRAEFIK_NETWORKRéseau Docker de Traefik (traefik par défaut)
TRAEFIK_ENTRYPOINTPoint d'entrée HTTPS de Traefik (websecure par défaut)
TRAEFIK_CERTRESOLVERRésolveur de certificats (letsencrypt par défaut)

Variables facultatives

VariableEffet
ORBITE_ALERT_WEBHOOKAdresse d'un webhook (n8n, Slack…) qui reçoit chaque erreur technique, y compris un test de restauration raté
ORBITE_BACKUP_HOURHeure de la sauvegarde nocturne (2 h par défaut)
ORBITE_BACKUP_KEEPNombre de sauvegardes conservées (14 par défaut)
ORBITE_ADMIN1 rouvre l'administration Django. À laisser absent en temps normal
Copier ORBITE_MEDIA_KEY et ORBITE_BACKUP_KEY hors du serveur, dès maintenant. Sans elles, les photos et les sauvegardes sont définitivement illisibles, même pour TST.

Premier compte manager

docker compose exec web python manage.py create_manager <identifiant> <Prénom> <Nom>

Exemple : create_manager marie.ngoma Marie Ngoma. Utiliser le vrai nom du manager : la documentation d'origine prenait « awa.mabiala Awa Mabiala » comme exemple. Noter le mot de passe défini ou affiché par la commande.

À sa première connexion, le manager active la double authentification : ORBITE affiche un code à scanner avec une application d'authentification (Google Authenticator, Microsoft Authenticator), puis huit codes de secours à garder en lieu sûr. Ensuite, chaque connexion demande le code à 6 chiffres de l'application.

Créer au moins deux managers. Avec deux managers actifs, les changements de paramètres et les confirmations de fraude exigent la validation du second, et un manager peut débloquer l'autre s'il perd son téléphone.

Recette technique

À dérouler après l'installation, puis après chaque mise à jour.

  1. docker compose ps : les trois conteneurs sont « healthy » ou « running ».
  2. L'adresse https://<domaine>/connexion/ s'ouvre avec un cadenas valide.
  3. Le manager se connecte et active sa double authentification.
  4. Un BA de test se connecte sur un vrai téléphone Android : le navigateur demande la position et la caméra, puis la prise de service fonctionne.
  5. Une visite de test apparaît au journal d'audit avec la bonne heure. Si l'heure est décalée par rapport à Brazzaville, le signaler avant le pilote : les compteurs « jour en cours » en dépendent.
  6. Le lendemain matin : docker compose exec web ls /data/backups montre la sauvegarde de la nuit, et le journal d'audit indique « Test de restauration réussi ».

Installation actuelle : points à vérifier

ORBITE tourne déjà sur le VPS. Avant les tests terrain :

  • Comptes de démonstration : les identifiants qui se terminent par .demo (mot de passe orbite2026) viennent du jeu de démonstration. S'ils existent en production, les suspendre depuis « Équipes et utilisateurs ».
  • Nom d'exemple : si le compte « Awa Mabiala » a été créé en suivant l'exemple de la documentation, créer les comptes des vrais managers, puis suspendre celui-ci.
  • Clés : vérifier que ORBITE_MEDIA_KEY et ORBITE_BACKUP_KEY sont copiées hors du serveur.
  • Sauvegardes : vérifier qu'une sauvegarde existe et qu'une copie part hors du serveur (voir plus bas).
  • Webhook : renseigner ORBITE_ALERT_WEBHOOK pour être prévenu d'une panne sans attendre un appel du terrain.

Préparer le pilote

  1. Équipes et comptes (Manager, « Équipes et utilisateurs ») : créer les équipes, puis les superviseurs, puis les BAs. Le mot de passe provisoire et le code d'activation ne s'affichent qu'une fois : les remettre en main propre.
  2. Points marchands (Manager, « Points et QR ») : importer un fichier CSV en UTF-8, séparateur ; ou ,. Utiliser d'abord « Simuler », qui n'écrit rien, puis « Importer ».
    code;nom;msisdn;segment;zone;equipe;ba;lat;lon;adresse
    PT-00001;Boutique Mama Nzola;055123456;A;Poto-Poto;Poto-Poto;grace.m;-4.2690;15.2780;avenue de la Paix
    PT-00002;Kiosque Mampassi;55987654;B;Poto-Poto;Poto-Poto;grace.m;;;marché Total

    Le numéro doit être un numéro Airtel (04 ou 05) ; un numéro à 8 chiffres est complété par le 0 initial. Sans coordonnées, le point est recensé au premier passage. ba est l'identifiant du BA qui a le point en portefeuille.

  3. QR : imprimer la planche de chaque équipe sur étiquettes autocollantes et les poser chez les marchands. Imprimer aussi des QR neufs pour les créations de points.
  4. Tournées : rien à faire. Elles se génèrent à la première ouverture de l'application par le BA, chaque jour.
  5. Paramètres : vérifier périmètre, précisions GPS, seuils du score, délai d'escalade, taux de contre-visite et taille des tournées.
Conformité. Avant d'activer de vrais agents : responsable du traitement désigné, déclaration à la CNPD, contrat de sous-traitance avec TST, notice d'information des agents sur la géolocalisation pendant les heures de service, hébergement validé par la sécurité d'Airtel.

Exploitation et sauvegardes

Ce qui tourne seul

  • Toutes les 5 minutes : escalade des alertes en retard, alertes d'inactivité, tirage des contre-visites, expiration des validations en attente.
  • Chaque nuit (2 h par défaut) : sauvegarde chiffrée de la base et des photos, test de restauration dans une base jetable, purge des durées de conservation (positions 90 jours, selfies 30 jours, photos 13 mois).

Aucune crontab n'est à créer sur le VPS : le conteneur scheduler s'en charge.

Sauvegardes à la demande

docker compose exec web python manage.py backup_orbite --check   # sauvegarde immédiate, vérifiée
docker compose exec web python manage.py restore_check           # re-tester la dernière sauvegarde
docker compose exec web ls /data/backups                          # lister les sauvegardes

Copier les sauvegardes hors du serveur

Une sauvegarde restée sur le VPS ne protège pas contre la perte du VPS. Les fichiers sont chiffrés : on peut les copier sans risque, à condition de garder les clés ailleurs.

cd /opt/orbite-app && docker compose cp web:/data/backups /root/orbite-backups
# puis, depuis le PC Windows (PowerShell) :
scp -r root@<ip-du-vps>:/root/orbite-backups .

À automatiser chaque nuit vers un autre serveur ou un stockage de l'entreprise.

Journaux

docker compose logs --tail=100 web
docker compose logs web | grep <référence>    # référence affichée à l'utilisateur en cas d'erreur

Mettre à jour

Hors des heures de terrain, quand aucun BA n'envoie de visites.

  1. Sauvegarder et vérifier :
    cd /opt/orbite-app
    docker compose exec web python manage.py backup_orbite --check
  2. Garder une copie du code actuel :
    cd /opt && cp -a orbite-app orbite-app.avant-$(date +%F)
  3. Décompresser la nouvelle version dans le même dossier. Le fichier .env n'est pas dans l'archive : il est conservé.
    unzip -o orbite-app.zip -d /opt
  4. Reconstruire et vérifier :
    cd /opt/orbite-app
    docker compose up -d --build
    docker compose exec web python manage.py migrate
    docker compose ps
    docker compose logs --tail=50 web
  5. Dérouler la recette technique.
Toujours le même nom de dossier. Docker nomme les volumes d'après le dossier. Décompresser dans /opt/orbite-app2 créerait une base, des photos et des sauvegardes vides : l'application repartirait de zéro.

Cas particuliers

  • Version installée antérieure au durcissement de sécurité : chaque téléphone déjà lié doit recevoir un nouveau code d'activation (« Changer de téléphone »).
  • Version installée antérieure au chiffrement des photos : lancer une fois docker compose exec web python manage.py encrypt_media.

Retour arrière

cd /opt && mv orbite-app orbite-app.echec && mv orbite-app.avant-AAAA-MM-JJ orbite-app
cd orbite-app && docker compose up -d --build

Si la nouvelle version a modifié la base, l'ancien code peut ne plus fonctionner avec elle : passer alors par la restauration de la sauvegarde prise à l'étape 1.

Restaurer après incident

Sur un serveur neuf, ou sur une installation dont la base est vide :

  1. Installer ORBITE comme ci-dessus avec le même .env, donc les mêmes clés.
  2. Copier la sauvegarde dans le conteneur :
    docker compose cp orbite-AAAAMMJJ-HHMMSS.obak web:/data/backups/
  3. Restaurer :
    docker compose exec web python manage.py restore_orbite /data/backups/orbite-AAAAMMJJ-HHMMSS.obak

La restauration est refusée si la base contient déjà des points ou des visites. L'option --force passe outre : ne l'utiliser qu'en sachant exactement ce qui sera écrasé.

Commandes de référence

Toutes se lancent depuis /opt/orbite-app, préfixées par docker compose exec web python manage.py.

CommandeUsage
create_manager id Prénom NomCréer un compte manager
reset_2fa idRéinitialiser la double authentification d'un manager, si aucun autre manager ne peut le faire
backup_orbite [--check]Sauvegarde chiffrée, avec test de restauration si --check
restore_check [fichier]Tester une sauvegarde dans une base jetable, sans toucher à la production
restore_orbite fichierRestauration réelle, base vide exigée
encrypt_mediaChiffrer les photos encore stockées en clair
purge_retentionAppliquer les durées de conservation (déjà faite chaque nuit)
seed_demoJeu de démonstration. Jamais en production

Dépannage

SymptômeQue faire
Un conteneur n'est pas « healthy »docker compose logs --tail=100 web. Le plus souvent, une valeur obligatoire manque dans .env.
Page inaccessible ou sans cadenasVérifier le DNS du sous-domaine, puis TRAEFIK_NETWORK, TRAEFIK_ENTRYPOINT et TRAEFIK_CERTRESOLVER.
GPS ou caméra refusés sur le téléphoneVérifier le HTTPS, puis les autorisations du site dans le navigateur.
Message d'erreur avec une référencedocker compose logs web | grep <référence>
Manager bloqué par la double authentificationUn autre manager la réinitialise depuis la console, avec un motif. Sinon : reset_2fa identifiant.
Compte bloqué après des erreurs de mot de passeBlocage automatique de 15 minutes après 5 échecs. Attendre.
Besoin de l'administration DjangoElle est fermée en production, car elle contourne la double authentification. ORBITE_ADMIN=1 puis docker compose up -d la rouvre ; retirer la ligne juste après.
Photos illisibles après restaurationORBITE_MEDIA_KEY n'est pas celle de l'ancien serveur.