06 Déploiement
Stratégie en 3 phases
- Pilote (Golden Sample) : 1 CloudGate parfaitement configurée, validée end-to-end contre les endpoints cibles
- Export config + flow LuvitRED sur CloudGate Universe → version
cloudgate-prod-v1.0 - Clones : nouvelles CG provisionnées en pulling cette version depuis CloudGate Universe
Phase 1 — Configurer le Golden Sample
1.1 Connexion initiale
Câble Ethernet entre poste d'admin et CG. IP LAN CG à 192.168.42.1 (configurable via l'admin web pour éviter les conflits LAN).
| Web admin | http://192.168.42.1 (admin / $ADMIN_PASS) |
| LuvitRED canvas | http://192.168.42.1:8080 |
| SSH | sshpass -p '$ADMIN_PASS' ssh admin@192.168.42.1 + algos legacy |
1.2 Activer LoRa (Cloud Wizard)
Web admin → Configuration → Cloud Wizard → activer LoRa server + LoRa app + Forwarder EU868.
1.3 Déployer le canvas LuvitRED
Importer dans LuvitRED admin → menu Import → From Clipboard → coller le contenu de deploy_flow.json :
# depuis la machine d'admin
sshpass -p '$ADMIN_PASS' scp -o KexAlgorithms=+diffie-hellman-group1-sha1 \
-o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedAlgorithms=+ssh-rsa \
deploy_flow.json admin@192.168.42.1:/tmp/
# (optionnel) backup du flow.json existant
sshpass -p '$ADMIN_PASS' ssh -o ... admin@192.168.42.1 \
"cp /etc/luvitred/flow.json /etc/luvitred/flow.json.bak.$(date +%s)"
1.4 Configurer les globals via console Lua ou inject startup
Une seule modification du fn_startup_init avec les valeurs cibles :
global.iobase_host = 'iobase.example.com'
global.dap_host = 'dap.example.com'
global.iobase_site = 'site_a'
global.iobase_datasource = 'transportation'
global.iobase_metrics_default = '["50001m_iot_pit002","50001m_iot_tt002"]'
global.asystom_url = 'https://advisor.example.com'
global.asystom_auth_b64 = '<base64(user:password)>'
global.asystom_network = 'cloudgate-XX'
global.asystom_client = '<asystom_client_id>'
1.5 Enrôlement DAP
- Tirer inject
DAP register - Vérifier
DAP_REGISTER_OK device_code=DC...dans le debug - L'administrateur IoBase valide le device dans le portail (« Services et équipements » → « Valider l'équipement »). Sans cette étape, l'appel suivant retournera HTTP 425.
- Tirer inject
DAP get token - Vérifier
DAP_TOKEN_OK+/mnt/data/luvitred/dap_state.jsonécrit
1.6 Test E2E
- Une balise Asystom à proximité, magnet × 3, vérifier Join
- Une trame uplink réelle → tracer la chaîne dans le debug
- POST IoBase 200 visible côté Indaba
- POST Asystom 201 visible côté Advisor
- Test offline : débrancher LTE 1 min → trames en queue → rebrancher → replay OK
Phase 2 — Export Golden Sample
2.1 Backup local
# Flow LuvitRED export
curl -b /tmp/lc.cookies http://192.168.42.1:8080/flows > cloudgate-prod-v1.0.flow.json
# Config CG export
http://192.168.42.1 → Configuration → Export → cloudgate-prod-v1.0.tar.gz
# Tokens DAP (NE PAS PARTAGER)
sshpass -p '...' scp ... admin@192.168.42.1:/mnt/data/luvitred/dap_state.json \
./cloudgate-prod-v1.0.dap_state.SECRET.json
2.2 Upload sur CloudGate Universe
CloudGate Universe → Devices → Configurations → New Version → upload cloudgate-prod-v1.0.tar.gz. Un compte CloudGate Universe valide est requis (à demander à l'administrateur de la flotte).
Phase 3 — Cloner sur d'autres CloudGates
3.1 Provisioning du clone
- Factory reset de la nouvelle CG (web admin → Reset)
- Câble + login admin / $ADMIN_PASS
- Configuration → Provisioning → Pull from CloudGate Universe → cloudgate-prod-v1.0
- La CG redémarre avec la même config (LoRa + forwarder + flow LuvitRED)
3.2 Spécifique au site
Modifier sur la nouvelle CG :
global.cloudgate_device_name→cloudgate-XX(XX = numéro de site)global.iobase_site→ identifiant du site cible- Refaire l'enrôlement DAP (le device est nouveau dans IoBase) — l'administrateur IoBase valide
3.3 Enrôler les balises du site
Voir Chap. 05.
Accès distant — Cloudflare Tunnel
L'accès distant aux interfaces locales de la CG (admin web port 80, LuvitRED 8080, SSH) repose sur l'agent cloudflared. L'agent ouvre une connexion sortante persistante vers le réseau Cloudflare ; aucun port entrant n'est exposé sur la CG. L'URL publique (ex. cloudgate-XX.<domaine>) est ensuite protégée par Cloudflare Access (One-time PIN par email, ou Google/Microsoft SSO).
localhost:80 / :8080
One-time PIN / SSO
auth Email PIN
Pré-requis
- Compte Cloudflare avec un domaine actif (zone DNS gérée par Cloudflare)
- Accès SSH root (ou équivalent) sur la CG pour installer le binaire dans
/usr/local/binet déposer la config dans/root/.cloudflared/ - Architecture CPU CG : ARMv5 → binaire
cloudflared-linux-arm
admin du firmware CG par défaut n'a pas accès root, et SSH root est désactivé. L'installation persistante de cloudflared requiert soit un firmware custom (CloudGate Universe) soit un wrapping via le canvas LuvitRED (qui tourne en root) pour copier le binaire dans /mnt/data et le lancer via os.execute au boot.
Étape 1 — Installer le binaire
# Architecture CG = ARMv5 (uname -m → armv5tejl)
wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-arm
chmod +x cloudflared-linux-arm
cp cloudflared-linux-arm /usr/local/bin/cloudflared
# Vérification
cloudflared version # → cloudflared version 2026.x.x
Étape 2 — Login + création du tunnel
# Génère un cert.pem dans /root/.cloudflared/
cloudflared tunnel login # ouvre une URL à autoriser dans le browser
# Crée le tunnel (1 par CG ou tunnel partagé selon stratégie)
cloudflared tunnel create cloudgate-XX
# → produit /root/.cloudflared/<UUID>.json (credentials, à conserver)
Étape 3 — config.yml (mapping ingress)
# /root/.cloudflared/config.yml
tunnel: <UUID_DU_TUNNEL>
credentials-file: /root/.cloudflared/<UUID>.json
ingress:
- hostname: cloudgate-XX.<domaine>
service: http://localhost:8080 # LuvitRED
- hostname: cloudgate-XX-admin.<domaine>
service: http://localhost:80 # admin web
- service: http_status:404 # default catchall
Étape 4 — Routage DNS + service
# Crée le CNAME automatique sur la zone Cloudflare
cloudflared tunnel route dns cloudgate-XX cloudgate-XX.<domaine>
cloudflared tunnel route dns cloudgate-XX cloudgate-XX-admin.<domaine>
# Service système (survit au reboot)
cloudflared service install
systemctl enable cloudflared
systemctl start cloudflared
systemctl status cloudflared # vérifier "active (running)"
Étape 5 — Cloudflare Access (sécurisation de l'URL)
Sans Access, l'URL publique est ouverte au monde. Il faut ajouter une policy.
- Cloudflare Zero Trust → Access > Applications > Add an application
- Type : Self-hosted
- Application Name :
CloudGate XX· Domain :cloudgate-XX.<domaine>(ou wildcard*.<domaine>) - Policies : Allow · Include =
Emails ending in @<votre-domaine>ou liste explicite d'emails opérateurs - Identity Provider : One-time PIN par email (par défaut) ou Google/Microsoft SSO
Multi-CG : workflow d'ajout d'une nouvelle CG
- Installer
cloudflaredsur la nouvelle CG (étape 1) - Lier au tunnel existant OU en créer un par CG (étape 2)
- Ajouter le hostname
cloudgate-YY.<domaine>dans le dashboard Cloudflare (Networks > Tunnels > Edit > Public Hostname) - Si Access est sur wildcard
*.<domaine>, la policy s'applique automatiquement, sinon ajouter le hostname dans la liste de l'application
Points de vigilance
| Point | Vérification |
|---|---|
| Architecture CPU | uname -m sur la CG → confirmer armv5tejl avant download du binaire |
| Persistance service | systemctl is-enabled cloudflared doit retourner enabled |
| Credentials JSON | /root/.cloudflared/<UUID>.json est le secret qui authentifie le tunnel — backup chiffré, ne jamais commit en clair |
| Survie au reboot CG | Tester un reboot complet et vérifier que le tunnel remonte sans intervention (cloudflared tunnel info cloudgate-XX côté Cloudflare) |
| Latence opérateur | Cloudflare ajoute ~50–150 ms (edge le plus proche). Acceptable pour admin web/SSH, à mesurer si flux temps réel requis. |