Architecture WireGuard Mesh

Architecture

Les 3 serveurs forment un mesh : chacun parle directement aux deux autres. Marseille et Albi peuvent communiquent en direct, sans passer par OVH.

        VPS OVH (10.0.0.1, eth0)
        IP publique fixe
        Portainer UI · exit node OVH
              /        \
         tunnel        tunnel
            /              \
  Marseille               Albi
  10.0.0.2               10.0.0.3
  enp4s0                 enp2s0
  LAN 192.168.1.0/24     LAN 192.168.2.0/24
  Portainer Agent        Portainer Agent + Home Assistant/Frigate
            \              /
             tunnel direct P2P
            (sauvegardes rsync)

Les besoins fonctionnelles & techniques

Cette architecture couvre des besoins bien définit qui pourrait résoudre des problématiques de sécurité entre plusieurs serveurs et services. 

Voici la liste des besoin couvert par cette architecture : 

Les définitions

Mesh (ou réseau maillé) est une topologie réseau où chaque nœud est connecté directement à plusieurs autres, sans point central obligatoire. Dans notre cas, les 3 serveurs forment un mesh : OVH parle à Marseille, OVH parle à Albi, et Marseille parle directement à Albi. C'est l'opposé du hub-and-spoke où tout passe obligatoirement par le centre. L'avantage : si OVH tombe, Marseille et Albi continuent de se parler directement.

Exit Node est le nœud par lequel votre trafic internet "sort" vers le monde. Quand vous activez un profil exit node, vous dites à votre appareil "fais passer tout ton trafic internet par ce serveur". Le site que vous visitez voit alors l'IP publique du serveur exit node, pas votre vraie IP. C'est exactement le principe d'un VPN classique grand public (NordVPN, ExpressVPN…), sauf qu'ici vous gérez vous-même le serveur de sortie. Le terme vient de Tailscale qui l'a popularisé, mais le mécanisme (AllowedIPs = 0.0.0.0/0 + masquerading) existe depuis les débuts de WireGuard.


Structure des fichiers

├── Configuration servers/
│   ├── ovh-wg0.conf           # Config WireGuard du VPS OVH
│   ├── marseille-wg0.conf     # Config WireGuard de Marseille
│   └── albi-wg0.conf          # Config WireGuard d'Albi
├── Confiiguration clients/
│   ├── ovh-exitnode.conf      # Client : IP publique = OVH
│   ├── mrs-exitnode.conf      # Client : IP publique = Marseille
│   ├── albi-exitnode.conf     # Client : IP publique = Albi
│   └── private-only.conf      # Client : réseau privé uniquement
├── Configuration Docker
│   ├── docker-compose-all.yml # docker-compose OVH + Marseille/Albi
├── Configuration Par-feu
│   ├── ovh-ufw.sh           # Config UFW du VPS OVH
│   ├── marseille-ufw.sh     # Config UFW de Marseille
│   └── albi-ufw.sh          # Config UFW d'Albi

Plan d'adressage complet

Matrice de sécurité

Profil client IP mesh Internet Mesh 10.0.0.x LAN MRS 192.168.1.x LAN Albi 192.168.2.x
ovh-exitnode 10.0.0.10 IP OVH
mrs-exitnode 10.0.0.20 IP MRS
albi-exitnode 10.0.0.30 IP Albi
private-only 10.0.0.40 propre
Serveur OVH 10.0.0.1
Serveur MRS 10.0.0.2
Serveur Albi 10.0.0.3

Double protection : 

Serveurs (peers fixes)

Serveur IP WireGuard IP publique LAN local Commentaire
VPS OVH 10.0.0.1 <IP_PUBLIQUE_OVH>
Marseille 10.0.0.2 <IP_PUBLIQUE_MRS> 192.168.1.0/24
Albi 10.0.0.3 <IP_PUBLIQUE_ALBI> 192.168.2.0/24

Clients (IP réservées)

IP Usage Profil Commentaire
10.0.0.10 Exit node OVH ovh-exitnode.conf IP publique = OVH
10.0.0.20 Exit node Marseille mrs-exitnode IP publique = Marseille + LAN
10.0.0.30 Exit node Albi albi-exitnode IP publique = Albi + LAN
10.0.0.40 Réseau privé OVH private-only.conf Réseau privé seul (Mesh), entrée par OVH
10.0.0.41 Réseau privé MRS private-only.conf Réseau privé seul (Mesh), entrée par MRS
10.0.0.42 Réseau privé Albi private-only.conf Réseau privé seul (Mesh), entrée par Albi

Commandes utiles

Vérifier l'état des tunnels

# Sur n'importe quel serveur
docker exec wireguard-ovh wg show       # OVH
docker exec wireguard-mrs wg show       # Marseille
docker exec wireguard-albi wg show      # Albi

# Résultat attendu : chaque peer doit avoir un "latest handshake" récent
# et un compteur de bytes "received/sent" qui monte

Tester la connectivité mesh

# Depuis OVH, pinger Marseille et Albi
docker exec wireguard-ovh ping 10.0.0.2 -c 3
docker exec wireguard-ovh ping 10.0.0.3 -c 3

# Depuis Marseille, pinger Albi directement (tunnel P2P)
docker exec wireguard-mrs ping 10.0.0.3 -c 3

# Vérifier que le LAN de Marseille est accessible depuis Albi
docker exec wireguard-albi ping 192.168.1.1 -c 3

Vérifier que Portainer UI n'est pas exposé

# Cette commande doit échouer (connexion refusée) depuis internet
curl -v http://<IP_PUBLIQUE_OVH>:9000

# Ceci doit fonctionner uniquement avec le VPN actif
curl -v http://10.0.0.1:9000

Tester une sauvegarde rsync inter-serveurs

# Depuis Marseille vers Albi (tunnel P2P direct)
docker run --rm --network host \
  -v /data/backups:/source:ro \
  instrumentisto/rsync-ssh \
  rsync -avz --progress /source/ user@10.0.0.3:/backup/marseille/

# Vérifier que le trafic ne passe PAS par OVH :
# Sur OVH pendant le rsync : docker exec wireguard-ovh wg show
# → les bytes du peer MRS et Albi ne doivent PAS augmenter

Générer un QR code pour mobile (iOS/Android)

# Installer qrencode
apt install qrencode

# Générer le QR pour le profil OVH exit node
qrencode -t ansiutf8 < clients/ovh-exitnode.conf

# Scanner avec l'app WireGuard sur le téléphone

Redémarrer un tunnel après modification de config

docker compose restart wireguard
# OU
docker exec wireguard-ovh wg syncconf wg0 <(wg-quick strip wg0)

Sécurité — points d'attention

  1. Ne jamais committer les clés privées dans Git. Ajouter *privatekey* au .gitignore.
  2. Portainer UI bind sur 10.0.0.1 uniquement — vérifier avec ss -tlnp | grep 9000.
  3. Portainer Agent bind sur 10.0.0.x uniquement — même vérification sur chaque serveur.
  4. Les fichiers .conf clients contiennent des clés privées — les traiter comme des mots de passe.
  5. Renouveler les clés si un appareil client est perdu ou compromis : supprimer son [Peer] de tous les serveurs et faire docker compose restart wireguard.
  6. Caveat UFW + Docker : Docker contourne UFW pour les ports qu'il publie. Ici Portainer est bindé sur 10.0.0.x → déjà limité au mesh. Pour tout futur conteneur, ne pas supposer qu'UFW protège un ports: "8080:8080".


Revision #12
Created 29 May 2026 13:24:18 by gpatruno
Updated 5 June 2026 09:31:45 by gpatruno