14 KiB
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.
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
port‑forward box. On l'évite en inversant le sens : le VPS (IPv4 publique stable) = serveur,
le NAS = client qui compose (dial‑out) → aucun port à ouvrir sur la box, pas d'IPv6.
Reco : WireGuard (moderne, léger, self‑hosted/souverain, reconnexion propre). Sur DSM 6.2.4 = conteneur Docker.
Sous‑réseau VPN choisi : 10.9.0.0/24 (VPS = 10.9.0.1, NAS = 10.9.0.2).
- Alternative simplicité : Tailscale (WireGuard clé‑en‑main, gère NAT/IPv6/clés) — service tiers.
- Alternative « réutiliser l'existant » : OpenVPN NAS‑serveur (voir annexe) — plus contraignant.
Étape 1 — VPN WireGuard (VPS serveur, NAS client)
- 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) - 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 - Vérifier :
ssh navier-vps 'ping -c2 10.9.0.2'(le VPS doit joindre le NAS). Le pont sera en10.9.0.2:8080. (Générer les clés :wg genkey|tee nas.key|wg pubkey>nas.pubcô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.1mais192.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 faitnavier-espace-web). État au 2026-07-20 :api.navier-instruments.comn'a aucun enregistrement DNS — cette étape n'a jamais été exécutée. Le pont est joint en interne, pas via un domaine public.
- DNS (LWS) :
api.navier-instruments.com A 78.138.45.8(+AAAAsi IPv6 VPS). - NPM (Nginx Proxy Manager) : Proxy Host
api.navier-instruments.com→→10.8.0.1:8080192.168.10.104:8080+ SSL Let's Encrypt (Force SSL, HTTP/2). - Vérifier :
curl -I https://api.navier-instruments.com/health→ 200.
É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@nasenenable→ 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
✅ RÉALISÉ (2026-07-13) — VPN opérationnel = Freebox IKEv2 (pas WireGuard)
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.confconnfreebox: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.secrets→VPSNavier : 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 bundleca-certificates.crtne 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). Idemscp/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 /interventions → 200. 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 config‑driven ; 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:intervbuildée sur le NAS (sudo docker build, node 22 alpine, tsc → dist). Dossier possédé par SteveC (chown -R) pour édition sans sudo ; docker exigesudosur 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 restartNE recharge PAS--env-file→ toujoursrm+runaprès un changement.env. - Volume data : le pont écrit un magasin de comptes/sessions dans
/data→ le volume/volume1/docker/sav-pont-datadoit appartenir à uid 1000 (node) :sudo chown -R 1000:1000. Sinon boucle de crashEACCES … accounts.tmp. .env(secrets jamais affichés) : adapters auto —DOLIBARR_BASE_URL+DOLIBARR_API_KEYremplis → 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 techniquecpont-sav(cléDOLAPIKEY). - 2 extrafields créés sur l'élément
fichinter(le pont les écrit enarray_options) :numero_serie(varchar 128) +sav_statut(varchar 64). Créés par : ligne dansllx_extrafields(elementtype='fichinter') + colonne ajoutée dansllx_fichinter_extrafields. Backup préalable :/volume1/docker/dolibarr-extrafields.backup.sql. Requêtesqlfilters=(ef.numero_serie:=:'…')→ 200. - Fix pont
createThirdparty: ajout decode_client: '-1'(numérotation auto). Sans ça, l'API Dolibarr (addonmod_codeclient_monkey) refuse la création de tiers avecErrorCustomerCodeRequired.-1= « automatic assignment » documenté dans la classeSocietedu cœur Dolibarr. Poussé sursav-integration(commitfix(sav/pont): createThirdparty envoie code_client:'-1'). - Aller‑retour réel validé : tiers (code auto) + fiche d'intervention avec
numero_serie/sav_statutcréé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-espace-client) 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 pourquoinavier-espace-webtourne 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-espace-client/ 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)
- URL publique de revue :
:8085est fermé au public (seul NPM 80/443 est ouvert). Pour une URL SSL → ajouter DNSespace.navier-instruments.com A → 78.138.45.8(LWS), puis NPM proxy hostespace.…→78.138.45.8:8085+ Let's Encrypt (même schéma questaging.=set $server 78.138.45.8). - Câblage données réelles : le front est encore un prototype (login factice +
var DATAen dur). À implémenter : login → JWT ThingsBoard (le pont le valide), puis lecture parc/SAV/factures via le pont (/interventionsfichinter). ⚠️ 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).