VPS/runbooks/vpn-nas-vps-pont-api.md

17 KiB
Raw Permalink Blame History

Runbook — VPN NAS↔VPS + pont SAV + api.navier-instruments.com

Objectif : exposer un seul service public (api.navier-instruments.com) qui relaie vers le pont (interne, sur le NAS), lequel parle à la gestion (Dolibarr) + ThingsBoard. La gestion n'est JAMAIS exposée. Documenté pour être reproductible — ne rien casser.


CONNEXION VPS↔NAS ACTUELLE (depuis 2026-08-06) — TUNNEL SSH INVERSÉ

SOURCE DE VÉRITÉ. L'IPsec/IKEv2 Freebox (plus bas) est RETIRÉ : il cassait à chaque reboot LWS (noyau externe 6.12 livré sans module ESP → tunnel mort, remontée SAV gelée). Le nouveau lien ne dépend ni du noyau LWS, ni de la Freebox — seulement « le NAS a un accès internet sortant » + « le VPS répond en SSH ».

Montage : le NAS compose (dial-out) un SSH sortant vers le VPS et publie 2 remote-forwards :

  • VPS 127.0.0.1:18080NAS localhost:8080 = pont SAV
  • VPS 127.0.0.1:11981NAS localhost:1981 = SSH du NAS (sauvegarde / accès distant)

Côté NAS (Synology) :

  • Clé dédiée /volume1/docker/sav-tunnel/id_tunnel, autorisée sur le VPS (~deploy/.ssh/authorized_keys, option restrict,port-forwarding = ce couple de clés ne peut RIEN faire d'autre que du forwarding).
  • Persistance = Planificateur de tâches DSM → tâche déclenchée « Au démarrage », utilisateur root, commande :
    KEY=/volume1/docker/sav-tunnel/id_tunnel
    while true; do
      ssh -i "$KEY" -o BatchMode=yes -o StrictHostKeyChecking=no -o ExitOnForwardFailure=yes \
          -o ServerAliveInterval=30 -o ServerAliveCountMax=3 \
          -N -R 18080:localhost:8080 -R 11981:localhost:1981 deploy@78.138.45.8
      sleep 5
    done
    
    La boucle while = reconnexion automatique (« autossh du pauvre »).

Côté VPS :

  • Le pont lit le NAS via le tunnel : /opt/navier-sav/.envNAS_PONT_URL=http://127.0.0.1:18080 (sauvegarde de l'ancien .env : /opt/navier-sav/.env.bak-pretunnel). Relais confirmé actif, remontée SAV restaurée (plus aucun « fetch failed »).
  • Atteindre le NAS depuis le VPS : ssh -p 11981 SteveC@127.0.0.1 (⚠️ plus 192.168.10.104 : l'ancienne route IPsec est morte).

Vérif de bout en bout :

ssh navier-vps 'curl -s http://127.0.0.1:18080/healthz'   # 200 => pont NAS joint via le tunnel
ssh navier-vps 'ss -ltn | grep -E ":18080|:11981"'        # les 2 forwards doivent être UP

Si ça retombe : vérifier que la tâche DSM tourne (Planificateur de tâches), que le NAS a internet, puis ss -ltn | grep 18080 sur le VPS. La tâche se relance seule ; sinon « Exécuter » dans DSM.


Architecture cible

public ──HTTPS──▶ api.navier-instruments.com
                  (VPS 78.138.45.8, Nginx Proxy Manager + SSL)
                        │
                        ▼  VPN OpenVPN (le VPS est client du serveur OpenVPN du NAS)
                  pont @navier/sav-pont  (NAS 10.8.0.1:8080)
                        │
              ┌─────────┴─────────┐
              ▼                   ▼
        Dolibarr (interne)   ThingsBoard (navier-cloud.com)

Inventaire (état 2026-07-13)

Élément Détail
NAS Synology N_instruments, LAN 192.168.10.104, DSM 6.2.4. SSH : ssh nas (SteveC, port 1981, clé id_ed25519_nas).
NAS = serveur OpenVPN server 10.8.0.0/24, proto udp6, port 1194, dev tun. NAS = 10.8.0.1. IP publique actuelle = IPv6 2a05:6e02:106c:fc10:....
Pont @navier/sav-pont (Node ≥20, TS). Source propre = repo Ecosystem-Navier/SAV/pont (Dockerfile, écoute :8080, métriques :9100). ⚠️ Le dossier /volume1/docker/sav/ du NAS est un dump de build cassé (noms mélangés) → NE PAS l'utiliser.
Gestion Dolibarr en Docker sur le NAS (/volume1/docker/dolibarr/, image tuxgasy/dolibarr + mariadb). Interne uniquement.
VPS 78.138.45.8, ssh navier-vps (user deploy). NPM (conteneur) fait le reverse-proxy + SSL.

Choix du VPN — recommandation : WireGuard (VPS serveur / NAS client)

Contrainte : le serveur OpenVPN du NAS est en udp6 + IP publique IPv6 → dépendance IPv6 ou portforward box. On l'évite en inversant le sens : le VPS (IPv4 publique stable) = serveur, le NAS = client qui compose (dialout) → aucun port à ouvrir sur la box, pas d'IPv6.

Reco : WireGuard (moderne, léger, selfhosted/souverain, reconnexion propre). Sur DSM 6.2.4 = conteneur Docker. Sousréseau VPN choisi : 10.9.0.0/24 (VPS = 10.9.0.1, NAS = 10.9.0.2).

  • Alternative simplicité : Tailscale (WireGuard cléenmain, gère NAT/IPv6/clés) — service tiers.
  • Alternative « réutiliser l'existant » : OpenVPN NASserveur (voir annexe) — plus contraignant.

Étape 1 — VPN WireGuard (VPS serveur, NAS client)

  1. VPS (root) — serveur :
    sudo apt-get update && sudo apt-get install -y wireguard
    umask 077; wg genkey | tee /etc/wireguard/vps.key | wg pubkey > /etc/wireguard/vps.pub
    # /etc/wireguard/wg0.conf :
    #   [Interface] Address=10.9.0.1/24  ListenPort=51820  PrivateKey=<contenu vps.key>
    #   [Peer]      PublicKey=<nas.pub>  AllowedIPs=10.9.0.2/32
    sudo systemctl enable --now wg-quick@wg0
    sudo ufw allow 51820/udp    # (ou règle firewall équivalente)
    
  2. NAS (Docker, root) — client (conteneur linuxserver/wireguard) :
    mkdir -p /volume1/docker/wireguard
    # /volume1/docker/wireguard/wg_confs/wg0.conf :
    #   [Interface] Address=10.9.0.2/32  PrivateKey=<contenu nas.key>
    #   [Peer]      PublicKey=<vps.pub>  Endpoint=<IP_PUBLIQUE_VPS>:51820  AllowedIPs=10.9.0.1/32  PersistentKeepalive=25
    docker run -d --name wireguard --cap-add NET_ADMIN --restart unless-stopped \
      -v /volume1/docker/wireguard:/config linuxserver/wireguard
    
  3. Vérifier : ssh navier-vps 'ping -c2 10.9.0.2' (le VPS doit joindre le NAS). Le pont sera en 10.9.0.2:8080. (Générer les clés : wg genkey|tee nas.key|wg pubkey>nas.pub côté NAS ; échanger les .pub entre les deux.)

Étape 2 — Déployer le pont (sur le NAS, proprement)

Depuis la source du repo (pas le dossier cassé). Le pont a un Dockerfile (écoute :8080).

# sur le NAS (root — Docker DSM 6)
mkdir -p /volume1/docker/sav-pont && cd /volume1/docker/sav-pont
# récupérer Ecosystem-Navier/SAV/pont (git clone ou rsync du sous-dossier)
docker build -t navier-sav-pont .
# pont.env = VRAIE config (URL Dolibarr interne, ThingsBoard, secrets) — à recréer proprement
docker run -d --name sav-pont --restart unless-stopped \
  -p 8080:8080 --env-file /volume1/docker/sav-pont/pont.env navier-sav-pont
curl -s http://localhost:8080/health   # doit répondre 200

Étape 3 — Exposer api.navier-instruments.com (VPS)

⚠️ PÉRIMÉ — ne pas appliquer tel quel. Cette étape date du plan WireGuard, abandonné (voir « RÉALISÉ » plus bas : la Freebox Pro filtre l'UDP sortant → VPN IKEv2 retenu). L'adresse du pont n'est pas 10.8.0.1 mais 192.168.10.104:8080. Rappel du piège réseau : un conteneur en bridge est SNAT hors du tunnel → il faut --network host (c'est ce que fait navier-espace-web). État au 2026-07-20 : api.navier-instruments.com n'a aucun enregistrement DNS — cette étape n'a jamais été exécutée. Le pont est joint en interne, pas via un domaine public.

  1. DNS (LWS) : api.navier-instruments.com A 78.138.45.8 (+ AAAA si IPv6 VPS).
  2. NPM (Nginx Proxy Manager) : Proxy Host api.navier-instruments.com10.8.0.1:8080192.168.10.104:8080 + SSL Let's Encrypt (Force SSL, HTTP/2).
  3. Vérifier : curl -I https://api.navier-instruments.com/health200.

Étape 4 — Brancher les consommateurs

  • Espace client, PWA SAV atelier, webapp → base API = https://api.navier-instruments.com (le seul point d'entrée).

Résilience / ne rien casser

  • VPN VPS : openvpn-client@nas en enable → reconnexion auto. Si NAS/box down → api. down → les consommateurs doivent dégrader proprement (cache / message « temporairement indisponible »).
  • Dolibarr jamais exposé — accessible seulement via le pont, scopé par client.
  • Ne pas exposer le port 9100 (métriques) publiquement.
  • Sauvegardes : base mariadb Dolibarr (sur le NAS) — vérifier la tâche de sauvegarde Synology.

Vérifs de bout en bout

ssh navier-vps 'ping -c2 10.8.0.1 && curl -s http://10.8.0.1:8080/health'
curl -I https://api.navier-instruments.com/health

RETIRÉ le 2026-08-06 — ancien VPN Freebox IKEv2 (remplacé par le tunnel SSH inversé, voir en tête)

Ne plus utiliser. Cassé par le reboot LWS du 31/07 (noyau 6.12 sans ESP). Remplacé par le tunnel SSH inversé (section « CONNEXION VPS↔NAS ACTUELLE » en tête). Le 06/08/2026, strongSwan a été arrêté + désactivé au démarrage sur le VPS, et /etc/ipsec.conf archivé dans /opt/navier-sav/ipsec-retired-2026-08-06/. Conservé ci-dessous pour l'historique uniquement.

WireGuard abandonné pour NAS↔VPS : le réseau du NAS (Freebox Pro) filtre l'UDP sortant (seul dport 53 passe, prouvé par tcpdump) → WireGuard (UDP) impossible depuis le NAS. Retenu : serveur VPN IKEv2 de la Freebox Pro.

Montage : VPS (client strongSwan) → 160189667.box.freepro.com (Freebox, VPN IKEv2) → LAN → NAS 192.168.10.104.

  • VPS /etc/ipsec.conf conn freebox : keyexchange=ikev2, right=160189667.box.freepro.com, rightsubnet=192.168.10.0/24 (route LAN seule — le VPS garde son net), leftauth=eap-mschapv2, leftid/eap_identity=VPSNavier, leftsourceip=%config, auto=start. Secrets : /etc/ipsec.secretsVPSNavier : EAP "<mdp>".
  • Fix cert indispensable : copier ISRG_Root_X1.pem (+X2) individuellement dans /etc/ipsec.d/cacerts/ (strongSwan ne lit qu'1 cert/fichier ; le bundle ca-certificates.crt ne suffit pas).
  • Persistance : systemctl enable strongswan-starter. Reconnexion : MOBIKE.
  • Vérif OK : ping 192.168.10.104 + curl http://192.168.10.104:4444 → 200.
  • Mobile : même serveur Freebox IKEv2 pour iPhone/Mac nativement (Réglages → VPN → IKEv2).

Accès NAS depuis n'importe quel réseau : quand on n'est PAS sur le LAN interne, le NAS reste joignable via le VPS : ssh -J navier-vps nas (ProxyJump — l'auth SSH reste boutàbout avec la clé NAS, seul le TCP transite par le VPS+tunnel). Idem scp/tar | ssh -J navier-vps nas.


RÉALISÉ (2026-07-13) — Pont SAV sur module INTERVENTION (fichinter), pas Ticket

DÉCISION ACTÉE (Steve + Tiago) : le SAV s'écrit en FICHE D'INTERVENTION Dolibarr (module Intervention, endpoints /interventions, table llx_fichinter), PAS en Ticket. Raison : le module Ticket renvoie 403 sur l'instance de prod (GET /tickets → 403), alors que GET /interventions200. Validé en direct sur Dolibarr 19. Cf. commit steve-dev #14 « bascule Tickets → fiches d'intervention », convergé dans la branche sav-integration.

Source du pont = branche sav-integration (repo Ecosystem-Navier, la plus à jour : pont modulaire Port + Adapters configdriven ; HttpDolibarrClient écrit en /interventions, /thirdparties, /stockmovements). L'ancien build (main) tapait /tickets → remplacé.

Déploiement du pont (NAS, /volume1/docker/sav-pont)

  • Image navier/sav-pont:interv buildée sur le NAS (sudo docker build, node 22 alpine, tsc → dist). Dossier possédé par SteveC (chown -R) pour édition sans sudo ; docker exige sudo sur DSM 6.
  • Conteneur : sudo docker run -d --name sav-pont --restart unless-stopped -p 8080:8080 --env-file .env -v /volume1/docker/sav-pont-data:/data navier/sav-pont:interv. ⚠️ docker restart NE recharge PAS --env-file → toujours rm + run après un changement .env.
  • Volume data : le pont écrit un magasin de comptes/sessions dans /data → le volume /volume1/docker/sav-pont-data doit appartenir à uid 1000 (node) : sudo chown -R 1000:1000. Sinon boucle de crash EACCES … accounts.tmp.
  • .env (secrets jamais affichés) : adapters auto — DOLIBARR_BASE_URL + DOLIBARR_API_KEY remplis → HttpDolibarrClient (fichinter) ; TB_BASE_URL → HttpThingsBoard. Ajoutés vs l'ancien : SESSION_SECRET (HMAC sessions LAN, sinon sessions perdues à chaque redémarrage), MEDIA_DIR=/data/media, SEED_SUPERVISOR_NAME=Steve / SEED_SUPERVISOR_PIN=1234 (superviseur initial — CHANGER le PIN).
  • Santé : GET /healthz{"status":"ok","deps":{"dolibarr":"http","thingsboard":"http","media":"local"}}.

Prérequis Dolibarr (fichinter) — appliqués et validés

Conforme au schéma officiel (wiki Extrafields / Table llx_extrafields) — pas de bricolage :

  • Module Intervention activé (GET /interventions → 200). Compte technique cpont-sav (clé DOLAPIKEY).
  • 2 extrafields créés sur l'élément fichinter (le pont les écrit en array_options) : numero_serie (varchar 128) + sav_statut (varchar 64). Créés par : ligne dans llx_extrafields (elementtype='fichinter') + colonne ajoutée dans llx_fichinter_extrafields. Backup préalable : /volume1/docker/dolibarr-extrafields.backup.sql. Requête sqlfilters=(ef.numero_serie:=:'…') → 200.
  • Fix pont createThirdparty : ajout de code_client: '-1' (numérotation auto). Sans ça, l'API Dolibarr (addon mod_codeclient_monkey) refuse la création de tiers avec ErrorCustomerCodeRequired. -1 = « automatic assignment » documenté dans la classe Societe du cœur Dolibarr. Poussé sur sav-integration (commit fix(sav/pont): createThirdparty envoie code_client:'-1').
  • Allerretour réel validé : tiers (code auto) + fiche d'intervention avec numero_serie/sav_statut créés puis supprimés (POST/GET/DELETE → 200) sur Dolibarr 19.

Chaîne complète prouvée

Mac (ssh -J) → VPS → tunnel IKEv2 → NAS pont :8080 (/interventions fichinter) → Dolibarr 19 réel. Le pont n'est pas exposé publiquement : l'espace client (VPS) le relaie en interne via le tunnel.


RÉALISÉ (2026-07-13) — Espace client déployé sur le VPS + pont /api (host-network)

Conteneur navier-espace-web (nginx:alpine) sur le VPS, sert le front statique de l'espace client (/home/deploy/navier-espace-web, rsync depuis ~/esp/navier-website/espace) sur :8085 et relaie /api/ → le pont http://192.168.10.104:8080/ (conf /home/deploy/espace.nginx.conf).

⚠️ Point réseau clé : atteindre le pont (tunnel IKEv2) depuis un conteneur

La politique IPsec ne capture QUE le trafic sourcé de l'IP VPN du VPS 192.168.2.1 (ip xfrm policy : src 192.168.2.1/32 dst 192.168.10.0/24). Un conteneur bridge est SNAT vers l'IP hôte → hors tunnel → curl pont = 000. Deux solutions :

  • RETENUE (sans firewall) : lancer le conteneur en --network host → il source depuis l'hôte (192.168.2.1) → le tunnel le transporte. C'est pourquoi navier-espace-web tourne en --network host (écoute :8085, proxy_pass direct vers le pont). Prouvé : /api/healthz → 200.
  • Alternative (si un conteneur bridge doit joindre le pont, ex. NPM en direct) : règle SNAT iptables -t nat -A POSTROUTING -s 172.16.0.0/12 -d 192.168.10.0/24 -j SNAT --to-source 192.168.2.1 (+ persistance). Non appliquée (changement firmware du VPS partagé = à valider hors auto-mode).

Commandes

# déploiement statique
rsync -az --delete ~/esp/navier-website/espace/ navier-vps:/home/deploy/navier-espace-web/
# conteneur (host-network pour joindre le pont via le tunnel)
sudo docker run -d --name navier-espace-web --restart unless-stopped --network host \
  -v /home/deploy/espace.nginx.conf:/etc/nginx/conf.d/default.conf:ro \
  -v /home/deploy/navier-espace-web:/usr/share/nginx/html:ro nginx:alpine
# vérif
curl http://127.0.0.1:8085/               # 200 (statique)
curl http://127.0.0.1:8085/api/healthz    # 200 (pont via tunnel)

RESTE (2 actions distinctes)

  1. URL publique de revue : :8085 est fermé au public (seul NPM 80/443 est ouvert). Pour une URL SSL → ajouter DNS espace.navier-instruments.com A → 78.138.45.8 (LWS), puis NPM proxy host espace.…78.138.45.8:8085 + Let's Encrypt (même schéma que staging. = set $server 78.138.45.8).
  2. Câblage données réelles : le front est encore un prototype (login factice + var DATA en dur). À implémenter : login → JWT ThingsBoard (le pont le valide), puis lecture parc/SAV/factures via le pont (/interventions fichinter). ⚠️ Le pont est scopé SAV-atelier (RBAC techniciens/superviseurs) : vérifier/ajouter les routes de lecture client avant de câbler (ne pas deviner l'API).