# Wireguard Docker

# Les commandes Wireguard

#### Générer une paire de clé privé/public

<span>Vous utiliserez les commandes intégrées </span>`wg genkey`<span>et </span>`wg pubkey`<span>pour créer les clés, puis ajouterez la clé privée au fichier de configuration de WireGuard.</span>

Génération de la clé privée

```bash
wg genkey >> private.key
```

Une fois la clé privé généré, il faut lui enlever les droits des utilisateurs et des groupes :

<span>La </span>`sudo chmod go=...`<span>commande supprime toutes les autorisations sur le fichier pour les utilisateurs et les groupes autres que l'utilisateur root afin de s'assurer que lui seul peut accéder à la clé privée.</span>

```bash
chmod go= private.key
```

Génération de la clé publique

```bash
cat private.key | wg pubkey >> public.key
```

####   


#### Ajouter un nouveau peer dans la configuration

```
wg set <interface_name> peer <public_key_client> allowed-ips <adress_ip_vpn_client>
```

/!\\ Ne pas oublier d’enregistrer les modifications effectuées sur la configuration serveur :   
`wg-quick save <interface_name>`

#### Prendre en compte des modifications de la configuration

```bash
wg-quick save <interface_name>
```

#### Afficher la configuration prise en compte 

```bash
wg show <interface_name>
```

#### Supprimer un peer sur le serveur

Pour supprimer un peer de la configuration serveur on a besoin :

- du nom de l'interface
- de la clé public du peer à supprimer

```bash
wg set <interface_name> peer <public_key_peer> remove
```

Si le serveur se trouve dans un conteneur

```
docker exec <container_name> wg set <interface_name> peer <public_key_peer> remove
```

/!\\ Ne pas oublier d’gistrer les modifications effectuées sur la configuration serveur :   
`wg-quick save <interface_name>`

#### Comment surveiller qui se connecter à votre VPN Wireguard ? 

La chose la plus simple que vous puissiez faire est de vous connecter en SSH à chacun des hôtes WireGuard sur votre réseau, et d'utiliser l'affichage d'état intégré de WireGuard pour vérifier l'état actuel de chaque interface et de chaque pair. Cela peut être faisable si vous n'avez que quelques serveurs VPN primaires à travers lesquels vos points de terminaison se connectent (plutôt qu'un réseau de points de terminaison connectés point à point).

Si vous vous connectez en SSH à un hôte exécutant WireGuard, vous pouvez obtenir un affichage en ligne de commande de chaque interface WireGuard active sur l'hôte, ainsi qu'une liste de chaque pair configuré pour l'interface, via la commande `wg` :

```bash
sudo wg show
```

```bash
interface: wg1
  public key: /TOE4TKtAqVsePRVR+5AA43HkAK5DSntkOCO7nYq5xU=
  private key: (hidden)
  listening port: 51821

peer: fE/wdxzl0klVp/IR8UcaoGUMjqaWi3jAd7KzHKFS6Ds=
  endpoint: 172.19.0.8:51822
  allowed ips: 10.0.0.2/32
  latest handshake: 1 minute, 22 seconds ago
  transfer: 3.48 MiB received, 33.46 MiB sent

peer: jUd41n3XYa3yXBzyBvWqlLhYgRef5RiBD7jwo70U+Rw=
  endpoint: 172.19.0.7:51823
  allowed ips: 10.0.0.3/32
  latest handshake: 2 hours, 3 minutes, 34 seconds ago
  transfer: 1.40 MiB received, 19.46 MiB sent
```

Chaque pair répertorié comprendra la clé publique utilisée par le pair, ainsi que quatre autres champs :

<span style="text-decoration: underline;">**point final**</span>  
Adresse IP publique actuelle (et port UDP) utilisée par l'homologue. Cette valeur est mise à jour à partir de la valeur initialement configurée pour l'homologue chaque fois que l'interface locale reçoit un nouveau paquet de l'homologue avec une adresse source (ou un port) différente.

**<span style="text-decoration: underline;">ips autorisés</span>**  
Adresses IP que l'interface WireGuard locale acheminera vers le pair.

**<span style="text-decoration: underline;">dernier handshake</span>**  
Si l'interface locale s'est connectée avec succès au pair distant depuis que l'interface a été démarrée, ceci indique la dernière fois que la connexion a été recodée. La "poignée de main" de reconnexion se produit toutes les 2 ou 3 minutes lorsque la connexion est activement utilisée (et uniquement lorsqu'elle est utilisée), ce qui vous donne une bonne approximation de la dernière fois que la connexion a été active. Ce champ sera omis si l'interface n'a pas réussi à se connecter à l'homologue depuis le démarrage de l'interface.

**<span style="text-decoration: underline;">transfert</span>**  
Si l'interface locale a tenté de se connecter à l'homologue distant depuis le démarrage de l'interface, ce champ indique la quantité de données reçues et envoyées à l'homologue. Ce champ sera omis si l'interface n'a pas tenté de se connecter à l'homologue depuis le démarrage de l'interface.

Les inconvénients évidents de l'utilisation de cette interface comme seul outil de surveillance sont que vous devez garder une session SSH ouverte sur chaque hôte que vous souhaitez surveiller, et que vous ne pouvez voir que ce qui se passe actuellement (ou la dernière fois que chaque pair était actif) - et non ce qui s'est passé aux moments spécifiques que vous pourriez vouloir examiner ou analyser.

# Mise en place de Wireguard Serveur

> WireGuard® est un VPN extrêmement simple, rapide et moderne qui utilise une cryptographie de pointe. Il se veut considérablement plus performant qu'OpenVPN.
> 
> WireGuard est conçu comme un VPN à usage général fonctionnant aussi bien sur des interfaces embarquées que sur des superordinateurs, adapté à de nombreuses circonstances différentes.
> 
> Initialement publié pour le noyau Linux, il est désormais multiplateforme (Windows, macOS, BSD, iOS, Android) et largement déployable. Il fait actuellement l'objet d'un développement intensif, mais il peut déjà être considéré comme la solution VPN la plus sûre, la plus facile à utiliser et la plus simple du secteur.

image docker : [https://github.com/linuxserver/docker-wireguard](https://github.com/linuxserver/docker-wireguard)

###   


### Utilisation de l'image docker

##### **<span style="text-decoration: underline;">Mode serveur</span>**

Si la variable d'environnement `PEERS` est définie à un nombre ou à une liste de chaînes séparées par une virgule, le conteneur fonctionnera en mode serveur et les confs serveur et pair/client nécessaires seront générées.

Les qr codes de configuration des pairs/clients seront affichés dans le journal de docker si `LOG_CONFS` est défini à `true`. Ils seront également sauvegardés au format texte et png sous `/config/peerX` dans le cas où `PEERS` est une variable et un entier ou `/config/peer_X` dans le cas où une liste de noms a été fournie à la place d'un entier.

Les variables `SERVERURL`, `SERVERPORT`, `INTERNAL_SUBNET`, `PEERDNS`, `INTERFACE`, `ALLOWEDIPS` et `PERSISTENTKEEPALIVE_PEERS` sont des variables optionnelles utilisées pour le mode serveur. Toute modification de ces variables d'environnement déclenchera la régénération des confs du serveur et des pairs. Les confs pairs/clients seront recréées avec les clés privées/publiques existantes.   
*--&gt; Supprimez les dossiers des pairs pour que les clés soient recréées en même temps que les confs.*

Pour ajouter ultérieurement d'autres pairs/clients, vous devez incrémenter la variable d'environnement PEERS ou ajouter d'autres éléments à la liste et recréer le conteneur.

Pour afficher à nouveau les codes QR des pairs actifs, vous pouvez utiliser la commande suivante et lister les numéros de pairs comme arguments :  
`docker exec -it wireguard /app/show-peer 1 4 5` ou `docker exec -it wireguard /app/show-peer myPC myPhone myTablet` (Gardez à l'esprit que les codes QR sont également stockés sous forme de PNG dans le dossier config).

Les modèles utilisés pour la configuration du serveur et des pairs sont enregistrés dans le dossier `/config/templates`. Les utilisateurs avancés peuvent modifier ces modèles et forcer la génération de confs en supprimant `/config/wg0.conf` et en redémarrant le conteneur.

docker-compose :

```yaml
version: "2.1"

services:

  wireguard:
    image: lscr.io/linuxserver/wireguard:latest
    container_name: wireguard
    cap_add:
      - NET_ADMIN
      # - SYS_MODULE  # optional already active 
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/Paris
      - SERVERURL=vpn.domaine-name.com
      - SERVERPORT=51820
      - PEERS=pcApple,pcGamer,telUser1,castHome
      - PEERDNS=auto
      #- INTERNAL_SUBNET=10.13.13.0 #optional
      #- ALLOWEDIPS=0.0.0.0/0 #optional
      #- PERSISTENTKEEPALIVE_PEERS= #optional
      - LOG_CONFS=true
    volumes:
      - /etc/container-conf/wireguard/appdata/config:/config
      - /etc/container-conf/wireguard/lib/modules:/lib/modules
    ports:
      - 51820:51820/udp
    restart: unless-stopped

volumes:
 wireguard:
```

##### Paramètres 

Les images des conteneurs sont configurées à l'aide de paramètres transmis au moment de l'exécution (tels que ceux indiqués ci-dessus). Ces paramètres sont séparés par deux points et indiquent `<external>:<internal>` respectivement.

Par exemple, `-p 8080:80` expose le port `80` à l'intérieur du conteneur pour qu'il soit accessible à partir de l'IP de l'hôte sur le port `8080` à l'extérieur du conteneur.

<table id="bkmrk-parameter-function-5" style="width: 100%; height: 687.688px;"><thead><tr style="height: 29.7969px;"><th align="center" style="width: 17.3012%; height: 29.7969px;">Parameter</th><th style="width: 82.6988%; height: 29.7969px;">Function</th></tr></thead><tbody><tr style="height: 29.7969px;"><td align="center" style="width: 17.3012%; height: 29.7969px;">`<span style="font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Roboto, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;">51820/udp</span>`</td><td style="width: 82.6988%; height: 29.7969px;">wireguard port</td></tr><tr style="height: 29.7969px;"><td align="center" style="width: 17.3012%; height: 29.7969px;">`<span style="font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Roboto, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;">PUID=1000</span>`</td><td style="width: 82.6988%; height: 29.7969px;">for UserID - see below for explanation</td></tr><tr style="height: 29.7969px;"><td align="center" style="width: 17.3012%; height: 29.7969px;">`<span style="font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Roboto, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;">PGID=1000</span>`</td><td style="width: 82.6988%; height: 29.7969px;">for GroupID - see below for explanation</td></tr><tr style="height: 35.3906px;"><td align="center" style="width: 17.3012%; height: 35.3906px;">`<span style="font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Roboto, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;">TZ=Etc/UTC</span>`</td><td style="width: 82.6988%; height: 35.3906px;">specify a timezone to use, see this [list](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List).</td></tr><tr style="height: 63.375px;"><td align="center" style="width: 17.3012%; height: 63.375px;">`<span style="font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Roboto, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;">SERVERURL=vpn.domain.com</span>`</td><td style="width: 82.6988%; height: 63.375px;">IP externe ou nom de domaine de l'hôte docker. Utilisé en mode serveur. Si la valeur est auto, le conteneur essaiera de déterminer et de définir l'IP externe automatiquement.</td></tr><tr style="height: 46.5938px;"><td align="center" style="width: 17.3012%; height: 46.5938px;">`<span style="font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Roboto, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;">SERVERPORT=51820</span>`</td><td style="width: 82.6988%; height: 46.5938px;">Port externe pour l'hôte Docker. Utilisé en mode serveur.</td></tr><tr style="height: 46.5938px;"><td align="center" style="width: 17.3012%; height: 46.5938px;">`<span style="font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Roboto, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;">PEERS=1</span>`</td><td style="width: 82.6988%; height: 46.5938px;">Nombre de pairs pour lesquels créer des confs. Requis pour le mode serveur. Peut également être une liste de noms : myPC,myPhone,myTablet (alphanumérique uniquement).</td></tr><tr style="height: 63.3906px;"><td align="center" style="width: 17.3012%; height: 63.3906px;">`<span style="font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Roboto, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;">PEERDNS=auto</span>`</td><td style="width: 82.6988%; height: 63.3906px;">Serveur DNS défini dans les configurations homologue/client (peut être défini comme 8.8.8.8). Utilisé en mode serveur. La valeur par défaut est auto, ce qui utilise le DNS de l'hôte wireguard docker via la redirection CoreDNS incluse.</td></tr><tr style="height: 46.5938px;"><td align="center" style="width: 17.3012%; height: 46.5938px;">`<span style="font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Roboto, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;">INTERNAL_SUBNET=10.13.13.0</span>`</td><td style="width: 82.6988%; height: 46.5938px;">Sous-réseau interne pour le wireguard, le serveur et les pairs (à ne modifier qu'en cas de conflit). Utilisé en mode serveur.</td></tr><tr style="height: 80.1875px;"><td align="center" style="width: 17.3012%; height: 80.1875px;">`<span style="font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Roboto, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;">ALLOWEDIPS=0.0.0.0/0</span>`</td><td style="width: 82.6988%; height: 80.1875px;">Les IP/plages que les homologues pourront atteindre en utilisant la connexion VPN. Si elle n'est pas spécifiée, la valeur par défaut est : '0.0.0.0/0, ::0/0' Tout le trafic transitera par le VPN. Si vous souhaitez un tunnel divisé, réglez cette valeur sur les IP que vous souhaitez utiliser dans le tunnel ET sur l'IP du WG du serveur, par exemple 10.13.13.1.</td></tr><tr style="height: 80.1875px;"><td align="center" style="width: 17.3012%; height: 80.1875px;">`<span style="font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Roboto, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;">PERSISTENTKEEPALIVE_PEERS=</span>`</td><td style="width: 82.6988%; height: 80.1875px;">Réglé sur tous ou sur une liste de pairs séparés par des virgules (par exemple 1,4,laptop) pour que le serveur wireguard envoie des paquets keepalive aux pairs listés toutes les 25 secondes. Utile si le serveur est accessible via un nom de domaine et possède une IP dynamique. Utilisé uniquement en mode serveur.</td></tr><tr style="height: 46.5938px;"><td align="center" style="width: 17.3012%; height: 46.5938px;">`<span style="font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Roboto, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;">LOG_CONFS=true</span>`</td><td style="width: 82.6988%; height: 46.5938px;">Les codes QR générés seront affichés dans le journal du docker. Mettez false pour ignorer la sortie du journal.</td></tr><tr style="height: 29.7969px;"><td align="center" style="width: 17.3012%; height: 29.7969px;">`<span style="font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Roboto, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;">/config</span>`</td><td style="width: 82.6988%; height: 29.7969px;">Contains all relevant configuration files.</td></tr><tr style="height: 29.7969px;"><td align="center" style="width: 17.3012%; height: 29.7969px;">`<span style="font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Roboto, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;">/lib/modules</span>`</td><td style="width: 82.6988%; height: 29.7969px;">Host kernel modules for situations where they're not already loaded.</td></tr></tbody></table>

##### Ouverture des ports

Maintenant que le serveur est configuré il ne faut pas oublier d'ouvrir le port concerné.   
Dans notre cas nous devons ouvrir le port 51820 sur le serveur et sur la box internet car le serveur se trouve derrière une box internet.

Sur le serveur (avec `ufw`) :

```bash
sudo ufw allow 51820
```

Sur la box internet : *(Voir comment configurer la redirection de port sur le panneau de configuration de la box internet de votre fournisseur)*

##### Accès Container Docker via Wireguard

Pour accéder aux containers Docker du serveur via Wireguard il est nécessaire d'ouvrir le par-feu comme ci dessous :

Adresse IP du container Wireguard : 192.168.128.2 (`docker inspect <containername>`)

Via UFW : `sudo ufw allow from 192.168.128.2`

Ce qui donne la configuration suivante :

```ini
> ufw status numbered
Status: active

     To                         Action      From
     --                         ------      ----
[1] 22/tcp                     ALLOW IN    Anywhere                  
[2] 80/tcp                     ALLOW IN    Anywhere                   
[3] 443                        ALLOW IN    Anywhere                  
[4] Anywhere                   ALLOW IN    192.168.128.2                 
[5] 51820                      ALLOW IN    Anywhere                  
[6] 22/tcp (v6)                ALLOW IN    Anywhere (v6)             
[7] 80/tcp (v6)                ALLOW IN    Anywhere (v6)             
[8] 443 (v6)                   ALLOW IN    Anywhere (v6)              
[9] 51820 (v6)                 ALLOW IN    Anywhere (v6)
```

# Mise en place de Wireguard Client

Pour utiliser Wireguard en mode client, deux choix s'offre à vous :  
1- Le premier, vous créez un conteneur Docker en mode client  
2- Le deuxième vous installer le package et vous configurer Wireguard client directement sur votre machine.

# 1 - Via l'utilisation de l'image docker

### Via l'utilisation de l'image docker

Ne définissez pas la variable d'environnement `PEERS`. Déposez votre conf client dans le dossier config en tant que `/config/wg0.conf` et démarrez le conteneur.

Si vous obtenez des erreurs liées à IPv6 dans le journal et que la connexion ne peut pas être établie, modifiez la ligne `AllowedIPs` dans votre pair/client wg0.conf pour inclure uniquement `0.0.0.0/0` et non `::/0`; et redémarrez le conteneur.

docker-compose :

```yaml
version: "2.1"

services:

  wireguard:
    image: lscr.io/linuxserver/wireguard:latest
    container_name: wireguard
    cap_add:
      - NET_ADMIN
      # - SYS_MODULE  # optional already active 
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/Paris
      - LOG_CONFS=true
    volumes:
      - /etc/container-conf/wireguard/appdata/config:/config
      - /etc/container-conf/wireguard/lib/modules:/lib/modules
    ports:
      - 51820:51820/udp
    restart: unless-stopped
    sysctls:
      - net.ipv4.conf.all.src_valid_mark=

volumes:
 wireguard:
```

# 2 - Via l'utilisation du package Linux

### Via l'utilisation du package Wireguard

##### <span style="text-decoration: underline;">Sur le client</span>

<span style="text-decoration: underline;">**1/**</span> Tout d'abord vous devez installer wireguard sur la machine :

```bash
sudo apt-get install wireguard
```

Puis se déplacer dans le répertoire de wireguard, par défaut le dossier est vide :

```bash
root@linux: cd /etc/wireguard/
root@linux: ls -al
total 28
drwx------   2 root root  4096 juin  13 12:03 ./
drwxr-xr-x 166 root root 12288 juin  13 11:24 ../
```

<span style="text-decoration: underline;">**2/**</span> Maintenant nous allons générer la clé privé et la clé publique :

```bash
wg genkey | tee privatekey | wg pubkey | tee publickey
```

Nous avons maintenant 2 fichiers dans le dossier wireguard :

```bash
root@linux: wg genkey | tee privatekey | wg pubkey | tee publickey
WKtF71pM6wObswaXkbxJgwPhk8a6lqrPb9oKFjaGOmM=
root@linux: ls -al
total 28
drwx------   2 root root  4096 juin  14 15:55 .
drwxr-xr-x 166 root root 12288 juin  13 11:24 ..
-rw-r--r--   1 root root    45 juin  14 15:55 privatekey
-rw-r--r--   1 root root    45 juin  14 15:55 publickey
```

**<span style="text-decoration: underline;">3/</span>** Pour continuer la configuration il faut noter le contenu des 2 clés générés :

```
root@linux: cat privatekey 
iApdu05JqNGSp/r7PSpJ5Zqxs4kWSR6qYv9onitvsmo=

root@linux: cat publickey 
WKtF71pM6wObswaXkbxJgwPhk8a6lqrPb9oKFjaGOmM=
```

<p class="callout danger">Attention ne partagez jamais votre clé privé !!</p>

Clé privé : iApdu05JqNGSp/r7PSpJ5Zqxs4kWSR6qYv9onitvsmo=  
Clé publique : WKtF71pM6wObswaXkbxJgwPhk8a6lqrPb9oKFjaGOmM=

<span style="text-decoration: underline;">**4/a)**</span> Création du fichier de configuration Wireguard client :

```bash
touch wg0.conf
```

<span style="text-decoration: underline;">**4/b)**</span> Préparer dans un bloc note la configuration suivante :

Il faut bien veiller à remplacer les variables :

- `<private_key_client>` -&gt; Clé privé généré précédemment
- `<range_ip_vpn>` -&gt; Adresse IP VPN du client
- `<public_key_server>` -&gt; Clé publique du serveur (A récupérer sur le serveur)
- `<ip_server>` -&gt; Adresse IP du serveur
- `<port_server>` -&gt; Port écoutant sur le serveur

```bash
[Interface]
PrivateKey = <private_key_client>
Address = <range_ip_vpn>

[Peer]
###Public of the WireGuard VPN Server
PublicKey = <public_key_server>

### IP and Port of the WireGuard VPN Server
Endpoint = <ip_server>:<port_server>

### Allow all traffic
AllowedIPs = 0.0.0.0/0
```

<span style="text-decoration: underline;">**4/c)**</span> Editer le fichier de configuration en collant la configuration complété :

```bash
nano wg0.conf
# ou
vim wg0.conf
```

Ce qui donne :

```bash
[Interface]
PrivateKey = iApdu05JqNGSp/r7PSpJ5Zqxs4kWSR6qYv9onitvsmo=
Address = 192.168.10.15/24

[Peer]
###Public of the WireGuard VPN Server
PublicKey = <public_key_server>

### IP and Port of the WireGuard VPN Server
Endpoint = vpn.domaine-name.com:51820

### Allow all traffic
AllowedIPs = 0.0.0.0/0
```

<p class="callout info">Le reste de la configuration continue sur la partie serveur</p>

##### <span style="text-decoration: underline;">Sur le serveur</span>

> `wg0` est l'interface référençant tous les appareils pouvant se connecter au VPN.

Préparer la commande suivante :

```bash
wg set wg0 peer <public_key_client> allowed-ips <adress_ip_vpn_client>
```

Ce qui donne :

```bash
wg set wg0 peer WKtF71pM6wObswaXkbxJgwPhk8a6lqrPb9oKFjaGOmM= allowed-ips 192.168.10.15
```

Puis exécuter la commande.

Pour être sur du bon fonctionnement de la commande précédente, nous pouvons lister les clients enregistré dans le fichier de conf du serveur :

```bash
wg show wg0
```

Maintenant il faut confirmer et enregistrer la modification du fichier de configuration :

```bash
wg-quick save wg0
```

#####   


##### <span style="text-decoration: underline;">Sur le client</span>

Nous avons créer le client et nous l'avons enregistré dans la configuration serveur. Maintenant il nous reste plus qu'a démarrer le VPN sur le client :

```
root@linux: wg-quick up wg0
[#] ip link add wg0 type wireguard
[#] wg setconf wg0 /dev/fd/63
[#] ip -4 address add 10.13.13.6/32 dev wg0
[#] ip link set mtu 1420 up dev wg0
[#] wg set wg0 fwmark 51820
[#] ip -4 route add 0.0.0.0/0 dev wg0 table 51820
[#] ip -4 rule add not fwmark 51820 table 51820
[#] ip -4 rule add table main suppress_prefixlength 0
[#] sysctl -q net.ipv4.conf.all.src_valid_mark=1
[#] nft -f /dev/fd/63
```

**Vérification du fonctionnement du VPN côté client :**

```
ifconfig
```

**Vérification du fonctionnement du nouveau client côté serveur :**

```bash
wg show wg0
```

# 3 - via le logiciel Windows

source : https://www.youtube.com/watch?v=u8w6jIdU39s&amp;t=0s

# Diagnostic WireGuard — Linux avec NetworkManager (GNOME)

Guide de diagnostic pour les problèmes de connectivité WireGuard sur Linux Ubuntu avec NetworkManager, notamment l'absence d'accès aux services du réseau local du serveur VPN.

---

## Symptômes typiques

- Internet fonctionne via le VPN (`ping 8.8.8.8` OK)
- Le serveur VPN est joignable (`ping 10.13.13.1` OK)
- Les services accessibles uniquement via VPN (ex: `192.168.1.x`, `10.13.13.x`) sont **inaccessibles**
- Le même profil fonctionne sur un autre appareil (téléphone, autre OS)

---

## Étape 1 — Vérifier l'état du tunnel WireGuard

```bash
sudo wg show

```

Vérifier que :

- L'interface est bien active
- Un `latest handshake` récent est visible (tunnel actif)
- `allowed ips` contient bien `0.0.0.0/0, ::/0` ou les plages nécessaires

---

## Étape 2 — Vérifier les routes appliquées

```bash
# Routes globales (le VPN doit apparaître ici)
ip route show

# Routes spécifiques à l'interface WireGuard (remplacer "Home" par le nom de ton interface)
ip route show dev Home

```

**Problème détecté si :** `ip route show dev Home` ne retourne rien malgré un tunnel actif.

Cela indique que NetworkManager n'a pas injecté les routes dans la table de routage principale — bug connu de NetworkManager avec WireGuard.

---

## Étape 3 — Vérifier les règles de routage

```bash
ip rule show

```

Exemple de sortie révélant le problème :

```
0:      from all lookup local
31076:  from all lookup main suppress_prefixlength 0
31077:  not from all fwmark 0xcb8e lookup 52110
32766:  from all lookup main
32767:  from all lookup default

```

La règle `not from all fwmark 0xcb8e lookup 52110` indique que WireGuard utilise une table de routage séparée. Vérifier son contenu :

```bash
ip route show table 52110

```

---

## Étape 4 — Vérifier le DNS

```bash
resolvectl status

```

Vérifier que l'interface WireGuard apparaît avec le bon serveur DNS (ex: `10.13.13.1`).

```bash
# Test de résolution DNS via le tunnel
dig @10.13.13.1 monservice.domaine.local

```

---

## Étape 5 — Tester la connectivité par IP directe

Avant de corriger, tester si le problème est DNS ou routage :

```bash
# Ping du serveur VPN
ping 10.13.13.1

# Accès direct par IP à un service (sans nom de domaine)
curl -v http://IP_DU_SERVICE:PORT

```

- Si ça fonctionne par IP → problème DNS uniquement
- Si ça échoue par IP → problème de routage (continuer ci-dessous)

---

## Correction — Ajouter les routes manquantes

### Cas 1 : Le service est sur le réseau WireGuard (`10.13.13.x`)

```bash
sudo nmcli connection modify <NOM_CONNEXION> +ipv4.routes "10.13.13.0/24 10.13.13.1"
sudo nmcli connection reload

```

### Cas 2 : Le service est sur le LAN du serveur (`192.168.1.x` par exemple)

```bash
sudo nmcli connection modify <NOM_CONNEXION> +ipv4.routes "192.168.1.0/24 10.13.13.1"
sudo nmcli connection reload

```

> ⚠️ **Attention** : si ton PC est lui-même sur `192.168.1.x`, ajouter cette route crée un conflit. Dans ce cas, les services doivent être exposés directement sur l'IP WireGuard du serveur (`10.13.13.1`).

### Cas 3 : Tout le trafic doit passer par le VPN (full tunnel)

```bash
sudo nmcli connection modify <NOM_CONNEXION> +ipv4.routes "0.0.0.0/0 10.13.13.1"
sudo nmcli connection reload

```

> ⚠️ Cette route remplace la route par défaut. Si elle provoque une perte d'internet, la supprimer immédiatement (voir ci-dessous).

---

## Annuler une modification (rollback)

```bash
# Supprimer une route ajoutée par erreur
sudo nmcli connection modify <NOM_CONNEXION> -ipv4.routes "CIDR GATEWAY"

# Exemple
sudo nmcli connection modify Home -ipv4.routes "0.0.0.0/0 10.13.13.1"

sudo nmcli connection reload

```

Puis déconnecter et reconnecter le VPN depuis GNOME.

---

## Vérifier la configuration stockée

Les configs NetworkManager sont dans `/etc/NetworkManager/system-connections/` :

```bash
sudo ls /etc/NetworkManager/system-connections/
sudo cat /etc/NetworkManager/system-connections/<NOM>.nmconnection

```

Exemple de bloc `[ipv4]` correct avec routes :

```ini
[ipv4]
address1=10.13.13.3/32
dns=10.13.13.1;
method=manual
route1=192.168.1.0/24,10.13.13.1

```

---

## Checklist récapitulatif

<table id="bkmrk-v%C3%A9rification-command"><thead><tr><th>Vérification</th><th>Commande</th><th>Résultat attendu</th></tr></thead><tbody><tr><td>Tunnel actif</td><td>`sudo wg show`</td><td>`latest handshake` récent</td></tr><tr><td>Routes VPN présentes</td><td>`ip route show dev <interface>`</td><td>Au moins une route affichée</td></tr><tr><td>Règles de routage</td><td>`ip rule show`</td><td>Table WireGuard présente</td></tr><tr><td>DNS correct</td><td>`resolvectl status`</td><td>DNS = IP du serveur VPN</td></tr><tr><td>Ping serveur VPN</td><td>`ping 10.13.13.1`</td><td>Réponse OK</td></tr><tr><td>Accès service par IP</td><td>`curl -v http://IP:PORT`</td><td>Connexion établie</td></tr></tbody></table>

---

## Causes racines fréquentes

<table id="bkmrk-sympt%C3%B4me-cause-proba"><thead><tr><th>Symptôme</th><th>Cause probable</th></tr></thead><tbody><tr><td>`ip route show dev <iface>` vide</td><td>NetworkManager n'injecte pas les routes (bug NM+WireGuard)</td></tr><tr><td>DNS OK mais IP inaccessible</td><td>Réseau cible absent des `AllowedIPs` ou routes manquantes</td></tr><tr><td>IP accessible mais domaine KO</td><td>DNS mal configuré ou non utilisé par le système</td></tr><tr><td>Internet coupé après modification</td><td>Route `0.0.0.0/0` en conflit avec route par défaut WiFi</td></tr></tbody></table>

# Configuration WireGuard Mesh — Documentation complète

# 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 &amp; 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 :

- 1 - Se connecter au VPN des différents serveur 
    - Hériter de l'adresse IP publique associé
    - Accéder au réseau local associé au serveur
    - Ne pas accéder au réseau local des AUTRES serveurs
    - Par exemple, je suis connecté au VPN du serveur de Marseille. J'ai alors l'adresse IP public de la box internet de MRS, j'ai accès à tous les appareils du réseau local de la box internet. Par contre je ne peux pas voir les autres appareils du réseau local de la box d'Albi.
- 2 - Faire communiquer les différents serveurs dans un tunnel privé et sécurisé 
    - Chaque serveur est joignable via ce réseau privé
    - Les services Docker peuvent utiliser ce réseau privé pour communiquer avec les services des autres serveurs
    - Ce tunnel privé ne doit pas faire partie de la même configuration que le besoin 1
- 3 - Cette architecture doit fonctionner avec un seul et même Wireguard Docker par serveur

#### 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.

<div id="bkmrk-"><div>---

</div></div>#### 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

```

<div id="bkmrk--1"><div>---

</div></div>
### Plan d'adressage complet

#### Matrice de sécurité

<table class="code-line" data-line="15" dir="auto" id="bkmrk-profil-client-ip-mes"><thead class="code-line" data-line="15" dir="auto"><tr class="code-line" data-line="15" dir="auto"><th>Profil client</th><th>IP mesh</th><th>Internet</th><th>Mesh 10.0.0.x</th><th>LAN MRS 192.168.1.x</th><th>LAN Albi 192.168.2.x</th></tr></thead><tbody class="code-line" data-line="17" dir="auto"><tr class="code-line" data-line="17" dir="auto"><td>ovh-exitnode</td><td>10.0.0.10</td><td>IP OVH</td><td>✓</td><td>✗</td><td>✗</td></tr><tr class="code-line" data-line="18" dir="auto"><td>mrs-exitnode</td><td>10.0.0.20</td><td>IP MRS</td><td>✓</td><td>✓</td><td>✗</td></tr><tr class="code-line" data-line="19" dir="auto"><td>albi-exitnode</td><td>10.0.0.30</td><td>IP Albi</td><td>✓</td><td>✗</td><td>✓</td></tr><tr class="code-line" data-line="22" dir="auto"><td>private-only</td><td>10.0.0.40</td><td>propre</td><td>✓</td><td>✗</td><td>✗</td></tr><tr class="code-line" data-line="23" dir="auto"><td>Serveur OVH</td><td>10.0.0.1</td><td>—</td><td>✓</td><td>✗</td><td>✗</td></tr><tr class="code-line" data-line="24" dir="auto"><td>Serveur MRS</td><td>10.0.0.2</td><td>—</td><td>✓</td><td>—</td><td>✗</td></tr><tr class="code-line" data-line="25" dir="auto"><td>Serveur Albi</td><td>10.0.0.3</td><td>—</td><td>✓</td><td>✗</td><td>—</td></tr></tbody></table>

Double protection :

- (1) les LAN ne sont dans les AllowedIPs d'aucun peer serveur → WireGuard refuse de les router ;
- (2) UFW pose FORWARD = DROP et n'autorise le LAN qu'à l'IP exit-node du site concerné.

#### Serveurs (peers fixes)

<div id="bkmrk-serveur-ip-wireguard"><div><table class="code-line" data-line="15" dir="auto"><thead class="code-line" data-line="15" dir="auto"><tr class="code-line" data-line="15" dir="auto"><th>Serveur</th><th>IP WireGuard</th><th>IP publique</th><th>LAN local</th><th>Commentaire</th></tr></thead><tbody class="code-line" data-line="17" dir="auto"><tr class="code-line" data-line="17" dir="auto"><td>VPS OVH</td><td>10.0.0.1</td><td>&lt;IP\_PUBLIQUE\_OVH&gt;</td><td>—</td><td>—</td></tr><tr class="code-line" data-line="18" dir="auto"><td>Marseille</td><td>10.0.0.2</td><td>&lt;IP\_PUBLIQUE\_MRS&gt;</td><td>192.168.1.0/24</td><td>—</td></tr><tr class="code-line" data-line="19" dir="auto"><td>Albi</td><td>10.0.0.3</td><td>&lt;IP\_PUBLIQUE\_ALBI&gt;</td><td>192.168.2.0/24</td><td>—</td></tr></tbody></table>

</div></div>#### Clients (IP réservées)

<div id="bkmrk-ip-usage-profil-comm"><div><table class="code-line" data-line="22" dir="auto"><thead class="code-line" data-line="22" dir="auto"><tr class="code-line" data-line="22" dir="auto"><th>IP</th><th>Usage</th><th>Profil</th><th>Commentaire</th></tr></thead><tbody class="code-line" data-line="24" dir="auto"><tr class="code-line" data-line="24" dir="auto"><td>10.0.0.10</td><td>Exit node OVH</td><td>ovh-exitnode.conf</td><td>IP publique = OVH</td></tr><tr class="code-line" data-line="25" dir="auto"><td>10.0.0.20</td><td>Exit node Marseille</td><td>mrs-exitnode</td><td>IP publique = Marseille + LAN</td></tr><tr class="code-line" data-line="26" dir="auto"><td>10.0.0.30</td><td>Exit node Albi</td><td>albi-exitnode</td><td>IP publique = Albi + LAN</td></tr><tr class="code-line" data-line="27" dir="auto"><td>10.0.0.40</td><td>Réseau privé OVH</td><td>private-only.conf</td><td>Réseau privé seul (Mesh), entrée par OVH</td></tr><tr><td>10.0.0.41</td><td>Réseau privé MRS</td><td>private-only.conf</td><td>Réseau privé seul (Mesh), entrée par MRS</td></tr><tr><td>10.0.0.42</td><td>Réseau privé Albi</td><td>private-only.conf</td><td>Réseau privé seul (Mesh), entrée par Albi</td></tr></tbody></table>

</div></div><div id="bkmrk-plage-usage-profil-c"><div>---

</div></div>## Commandes utiles

#### Vérifier l'état des tunnels

```bash
# 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

```bash
# 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é

```bash
# 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

```bash
# 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)

```bash
# 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

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

```

<div id="bkmrk--2"></div>#### Sécurité — points d'attention

<div id="bkmrk-%23-configuration-wire"><div>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"`.

  
</div></div>

# Processus de déploiement

### Étape 1 — Générer les clés

Sur chaque serveur, générer une paire de clés :

```bash
# Sur OVH
wg genkey | tee /etc/wireguard/privatekey-ovh | wg pubkey > /etc/wireguard/publickey-ovh

# Sur Marseille
wg genkey | tee /etc/wireguard/privatekey-mrs | wg pubkey > /etc/wireguard/publickey-mrs

# Sur Albi
wg genkey | tee /etc/wireguard/privatekey-albi | wg pubkey > /etc/wireguard/publickey-albi

# Pour chaque client
wg genkey | tee privatekey-client | wg pubkey > publickey-client

```

### Étape 2 — Remplacer les placeholders

Dans tous les fichiers .conf, remplacer :

<div id="bkmrk-%3Ccle_privee_ovh%3E%C2%A0%E2%86%92-c"><div>- `<CLE_PRIVEE_OVH>` → contenu de privatekey-ovh
- `<CLE_PUBLIQUE_OVH>` → contenu de publickey-ovh
- `<CLE_PRIVEE_MRS>` → contenu de privatekey-mrs
- `<CLE_PUBLIQUE_MRS>` → contenu de publickey-mrs
- `<CLE_PRIVEE_ALBI>` → contenu de privatekey-albi
- `<CLE_PUBLIQUE_ALBI>` → contenu de publickey-albi
- `<IP_PUBLIQUE_OVH>` → IP publique du VPS OVH
- `<IP_PUBLIQUE_MRS>` → IP publique de la box Marseille
- `<IP_PUBLIQUE_ALBI>` → IP publique de la box Albi
- (idem pour les clés clients)

</div></div>### Étape 3 — Configuration des box internet

##### Box Marseille &amp; Box Albi

Effectuer dans l'interface admin de chaque box :

**Port forwarding :**

```
Protocole : UDP
Port externe : 51820
IP destination : 192.168.X.100 (IP locale du serveur)
Port destination : 51820

```

### Étape 4 — Déployer dans l'ordre

```bash
# 1. Démarrer le hub OVH en premier
ssh ovh "cd /opt/wireguard && docker compose up -d"

# 2. Démarrer Marseille
ssh marseille "cd /opt/wireguard && docker compose up -d"

# 3. Démarrer Albi
ssh albi "cd /opt/wireguard && docker compose up -d"

# Une fois wg0 créé, appliquer le pare-feu :
sudo bash ovh-ufw-setup.sh         # sur OVH
sudo bash marseille-ufw-setup.sh   # sur Marseille
sudo bash albi-ufw-setup.sh        # sur Albi
```

#### Pourquoi le conteneur WireGuard a besoin de host ? 

Le point dur, c'est le **routage et le NAT au niveau de l'hôte**. Tes exit-nodes et l'accès LAN reposent sur le fait que le trafic traverse le serveur entre `wg0` et l'interface physique (`enp4s0`, etc.), avec masquerading. Pour que ça fonctionne, `wg0` doit vivre dans le namespace réseau de l'hôte et UFW doit pouvoir filtrer ce trafic au niveau hôte.

Si tu mets WireGuard dans un réseau Docker isolé, `wg0` est créé dans le namespace du conteneur. Tu peux router le mesh entre conteneurs, mais dès que tu veux :

- faire sortir un client sur internet via l'IP publique du serveur (exit node),
- ou atteindre le LAN physique `192.168.x.0/24`,

tu dois faire ressortir le trafic du namespace conteneur vers l'hôte puis vers l'interface physique. C'est faisable mais ça demande des `iptables` supplémentaires et une gymnastique de routage qui annule l'intérêt de l'isolation. **Pour le rôle de passerelle VPN, host est le choix pragmatique.**

### Étape 5 — Vérification de sécurité

##### Note Docker (importante pour Home Assistant)

Après `ufw enable`, si les conteneurs (Home Assistant, Frigate…) perdent l'accès réseau, redémarrer Docker **une seule fois** pour qu'il replace ses règles FORWARD au-dessus de celles d'UFW :

```bash
sudo systemctl restart docker

```

À faire à un moment calme (cela redémarre HA et Frigate). En pratique HA en host n'a pas besoin de la chaîne FORWARD, donc ce redémarrage est rarement nécessaire — mais c'est le réflexe si un conteneur perd le réseau.

##### Vérifier les règles Par-feu

```bash
ufw status verbose
ufw route status                       # liste les règles FORWARD VPN
iptables -t nat -L POSTROUTING -n | grep MASQUERADE
```

#### Vérifier que Portainer n'est PAS exposé sur l'IP publique

```bash
# Depuis internet (doit échouer — connexion refusée ou timeout)
curl -v --max-time 5 http://<IP_PUBLIQUE_OVH>:9000

# Depuis le VPN avec private-only actif (doit fonctionner)
curl -v http://10.0.0.1:9000

```

#### Tester le cloisonnement LAN

```bash
# Avec private-only.conf actif, tenter d'atteindre le LAN de Marseille
ping 192.168.1.1    # doit échouer (pas de route + iptables DROP)
ping 192.168.2.1    # doit échouer

# Avec mrs-exitnode.conf actif
ping 192.168.1.1    # doit répondre (autorisé)
ping 192.168.2.1    # doit échouer (bloqué)

# Avec albi-exitnode.conf actif
ping 192.168.1.1    # doit échouer
ping 192.168.2.1    # doit répondre (autorisé)

```

#### Vérifier l'état du mesh

```bash
# Sur OVH — doit lister MRS et Albi avec handshake récent
docker exec wireguard-ovh wg show

# Exemple de sortie attendue :
# peer: <CLE_PUBLIQUE_MRS>
#   endpoint: <IP_MRS>:51820
#   allowed ips: 10.0.0.2/32
#   latest handshake: X seconds ago
#   transfer: X MiB received, X MiB sent

```

#### Vérifier les sauvegardes rsync (tunnel direct P2P)

```bash
# Depuis Marseille vers Albi — ne doit PAS faire monter les compteurs OVH
docker exec wireguard-mrs rsync -avz /data/ user@10.0.0.3:/backup/

# Pendant le rsync, vérifier sur OVH que les bytes N'augmentent PAS :
watch -n1 "docker exec wireguard-ovh wg show | grep -A4 'marseille\|albi'"
```

### Étape 6 — Configurer Portainer UI

<div id="bkmrk-ouvrir%C2%A0http%3A%2F%2F10.0.0"><div>1. Ouvrir [http://10.0.0.1:9000](http://10.0.0.1:9000/) avec le profil private-only.conf actif
2. Aller dans Environments &gt; Add environment &gt; Agent
3. Ajouter Marseille : URL = `10.0.0.2:9001`, nom = "Marseille"
4. Ajouter Albi : URL = `10.0.0.3:9001`, nom = "Albi"

</div></div>

# Configuration Wireguard Docker

#### Docker compose

```yaml
# =============================================================================
# docker-compose.yml — VPS OVH  (WireGuard Hub + Portainer UI)
# Version 3 — pare-feu géré par UFW (pas de règles dans wg0.conf)
# =============================================================================
# Arborescence :
#   /opt/wireguard-ovh/
#   ├── docker-compose.yml
#   └── wg-config/wg0.conf      (= servers/ovh-wg0.conf renommé)
#
# Démarrage :
#   docker compose up -d
#   sudo bash ovh-ufw-setup.sh   # APRÈS, pour que wg0 existe
# =============================================================================

services:

  wireguard:
    image: lscr.io/linuxserver/wireguard:latest
    container_name: wireguard-ovh
    # network_mode: host — cohabite sans souci avec d'autres conteneurs host
    # (ex : Home Assistant sur Albi). Indispensable pour que wg0 et le
    # routage soient au niveau de l'hôte, où UFW applique ses règles.
    network_mode: host
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/Paris
    volumes:
      - ./wg-config:/config
      # Accès au module kernel wireguard de l'hôte
      - /lib/modules:/lib/modules:ro
    restart: unless-stopped

  portainer:
    image: portainer/portainer-ce:latest
    container_name: portainer-ui
    # Bind sur l'IP WireGuard uniquement : invisible depuis l'IP publique OVH.
    ports:
      - "10.0.0.1:9000:9000"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - portainer-data:/data
    restart: unless-stopped
    depends_on:
      - wireguard

volumes:
  portainer-data:

---
# =============================================================================
# docker-compose.yml — Serveur Marseille  (WireGuard + Portainer Agent)
# wg-config/wg0.conf = servers/marseille-wg0.conf
# Lancer ensuite : sudo bash marseille-ufw-setup.sh
# =============================================================================

services:

  wireguard:
    image: lscr.io/linuxserver/wireguard:latest
    container_name: wireguard-mrs
    network_mode: host
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/Paris
    volumes:
      - ./wg-config:/config
      - /lib/modules:/lib/modules:ro
    restart: unless-stopped

  portainer-agent:
    image: portainer/agent:latest
    container_name: portainer-agent
    # Bind sur l'IP WireGuard de Marseille — joignable seulement via le mesh.
    ports:
      - "10.0.0.2:9001:9001"
    environment:
      - AGENT_PORT=9001
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /var/lib/docker/volumes:/var/lib/docker/volumes
    restart: unless-stopped
    depends_on:
      - wireguard

---
# =============================================================================
# docker-compose.yml — Serveur Albi  (WireGuard + Portainer Agent)
# wg-config/wg0.conf = servers/albi-wg0.conf
# Lancer ensuite : sudo bash albi-ufw-setup.sh
#
# Home Assistant / Frigate tournent déjà sur ce serveur : aucun changement
# requis pour eux. WireGuard en host cohabite avec HA en host.
# =============================================================================

services:

  wireguard:
    image: lscr.io/linuxserver/wireguard:latest
    container_name: wireguard-albi
    network_mode: host
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/Paris
    volumes:
      - ./wg-config:/config
      - /lib/modules:/lib/modules:ro
    restart: unless-stopped

  portainer-agent:
    image: portainer/agent:latest
    container_name: portainer-agent
    # Bind sur l'IP WireGuard d'Albi.
    ports:
      - "10.0.0.3:9001:9001"
    environment:
      - AGENT_PORT=9001
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /var/lib/docker/volumes:/var/lib/docker/volumes
    restart: unless-stopped
    depends_on:
      - wireguard
```

# Configuration Serveurs

#### Serveur OVH

```ini
# =============================================================================
# WireGuard — VPS OVH (Hub du mesh)
# IP WireGuard : 10.0.0.1/24
# Rôle : hub + exit node OVH + Portainer UI + entrée private-only (10.0.0.40)
# =============================================================================
#
#   - Les LAN (192.168.1.0/24 et 192.168.2.0/24) ne font pas parti des AllowedIPs
#     des peers serveurs. OVH ne "connaît" plus les LAN des sites physiques.
#   - La politique FORWARD passe à DROP par défaut : seul le trafic
#     explicitement autorisé est routé. Tout le reste est silencieusement jeté.
#   - Conséquence : un client connecté à OVH ne peut PAS atteindre
#     192.168.1.x ou 192.168.2.x, même s'il connaît l'adresse.
#
# PRÉREQUIS :
#   - Port UDP 51820 ouvert dans le firewall OVH ET dans UFW
#   - Vérifier le nom de l'interface réseau : ip link show
#     (peut être eth0, ens3, ens4, enp1s0 selon le VPS)
#   - ip_forward activé au niveau hôte (fait par le script UFW)
#
# =============================================================================

[Interface]
Address    = 10.0.0.1/24
ListenPort = 51820
PrivateKey = <CLE_PRIVEE_OVH>

# =============================================================================
# PEER : Serveur Marseille
# =============================================================================
[Peer]
PublicKey = <CLE_PUBLIQUE_MRS>
Endpoint  = <IP_PUBLIQUE_MRS>:51820

#   10.0.0.2/32   → IP WireGuard de MRS (mesh)
#   10.0.0.20/32  → client mrs-exitnode : son trafic retour repasse par MRS
#   10.0.0.41/32  → client private-only entré via MRS : retour via MRS
# Pas de 192.168.1.0/24 : OVH ne route jamais vers le LAN de Marseille.
AllowedIPs          = 10.0.0.2/32, 10.0.0.20/32, 10.0.0.41/32
PersistentKeepalive = 25


# =============================================================================
# PEER : Serveur Albi
# =============================================================================
[Peer]
PublicKey = <CLE_PUBLIQUE_ALBI>
Endpoint  = <IP_PUBLIQUE_ALBI>:51820

#   10.0.0.3/32   → IP WireGuard d'Albi (mesh)
#   10.0.0.30/32  → client albi-exitnode : retour via Albi
#   10.0.0.42/32  → client private-only entré via Albi : retour via Albi
AllowedIPs          = 10.0.0.3/32, 10.0.0.30/32, 10.0.0.42/32
PersistentKeepalive = 25


# =============================================================================
# PEER : Client ovh-exitnode
# Tout le trafic internet sort par OVH. IP publique = VPS OVH.
# =============================================================================
[Peer]
PublicKey  = <CLE_PUBLIQUE_CLIENT_OVH_1>
AllowedIPs = 10.0.0.10/32


# =============================================================================
# PEER : Client private-only entré via OVH
# =============================================================================
[Peer]
PublicKey  = <CLE_PUBLIQUE_CLIENT_PRIVATE_OVH>
AllowedIPs = 10.0.0.40/32
```

#### Serveur Marseille

```ini
# =============================================================================
# WireGuard — Serveur physique Marseille (Spoke)
# IP WireGuard : 10.0.0.2/24
# LAN local    : 192.168.1.0/24
# Rôle         : exit node MRS (+ accès LAN MRS) + Portainer Agent
#                + entrée private-only (10.0.0.41) + sauvegardes P2P avec Albi
# =============================================================================
#
# ACCÈS AU LAN 192.168.1.0/24 :
#   Autorisé UNIQUEMENT au client mrs-exitnode (10.0.0.20) via UFW.
#   Voir ufw/marseille-ufw-setup.sh pour les règles de filtrage.
#
#   Tout autre peer (OVH, Marseille, clients exit-MRS, private-only…)
#   est bloqué par le Pare-feu.
#
# PRÉREQUIS SUR LA BOX :
#   1. Port forwarding UDP 51820 → 192.168.1.100 (IP locale du serveur)
#
# =============================================================================

[Interface]
Address    = 10.0.0.2/24
ListenPort = 51820
PrivateKey = <CLE_PRIVEE_ALBI>


# =============================================================================
# PEER : VPS OVH
# =============================================================================
[Peer]
PublicKey = <CLE_PUBLIQUE_OVH>
Endpoint  = <IP_PUBLIQUE_OVH>:51820

# Destinations routées VERS OVH depuis Marseille :
#   10.0.0.1/32   → IP WireGuard d'OVH (mesh, Portainer UI)
#   10.0.0.10/32  → client ovh-exitnode : retour via OVH
#   10.0.0.40/32  → client private-only entré via OVH : retour via OVH
AllowedIPs          = 10.0.0.1/32, 10.0.0.10/32, 10.0.0.40/32
PersistentKeepalive = 25


# =============================================================================
# PEER : Serveur Albi (tunnel P2P direct — sauvegardes sans passer par OVH)
# =============================================================================
[Peer]
PublicKey = <CLE_PUBLIQUE_ALBI>
Endpoint  = <IP_PUBLIQUE_ALBI>:51820

# Destinations routées VERS Albi :
#   10.0.0.3/32   → IP WireGuard d'Albi (sauvegardes rsync/SSH)
#   10.0.0.30/32  → client albi-exitnode (symétrie mesh)
#   10.0.0.42/32  → client private-only entré via Albi
# Pas de 192.168.2.0/24 : MRS ne route jamais vers le LAN d'Albi.
AllowedIPs          = 10.0.0.3/32, 10.0.0.30/32, 10.0.0.42/32
PersistentKeepalive = 25


# =============================================================================
# PEER : Client mrs-exitnode (IP publique = MRS, accès LAN MRS)
# =============================================================================
[Peer]
PublicKey  = <CLE_PUBLIQUE_CLIENT_MRS>
AllowedIPs = 10.0.0.20/32


# =============================================================================
# PEER : Client private-only entré via MRS
# =============================================================================
[Peer]
PublicKey  = <CLE_PUBLIQUE_CLIENT_PRIVATE_MRS>
AllowedIPs = 10.0.0.41/32
```

#### Serveur Albi

```ini
# =============================================================================
# WireGuard — Serveur physique Albi (Spoke)
# IP WireGuard : 10.0.0.3/24
# Interface physique : enp2s0
# LAN local : 192.168.2.0/24
# Rôle : exit node Albi (+ accès LAN Albi) + Portainer Agent
#        + entrée private-only (10.0.0.42) + sauvegardes P2P avec MRS
# =============================================================================
#
# COHABITATION AVEC HOME ASSISTANT / FRIGATE :
#   WireGuard tourne en network_mode: host, comme Home Assistant.
#   Aucun conflit : plusieurs conteneurs peuvent partager la pile réseau
#   de l'hôte. Le filtrage FORWARD posé par UFW n'affecte pas la
#   communication HA <-> Frigate (trafic local ou géré par Docker),
#   il ne filtre que le trafic VPN routé.
#
# ACCÈS AU LAN 192.168.2.0/24 :
#   Autorisé UNIQUEMENT au client albi-exitnode (10.0.0.30) via UFW.
#
# PRÉREQUIS BOX ALBI :
#   - Port forwarding UDP 51820 → 192.168.2.100 (IP locale du serveur)
#
# =============================================================================

[Interface]
Address    = 10.0.0.3/24
ListenPort = 51820
PrivateKey = <CLE_PRIVEE_ALBI>


# =============================================================================
# PEER : VPS OVH
# =============================================================================
[Peer]
PublicKey = <CLE_PUBLIQUE_OVH>
Endpoint  = <IP_PUBLIQUE_OVH>:51820

#   10.0.0.1/32   → IP WireGuard d'OVH
#   10.0.0.10/32  → client ovh-exitnode : retour via OVH
#   10.0.0.40/32  → client private-only entré via OVH
AllowedIPs          = 10.0.0.1/32, 10.0.0.10/32, 10.0.0.40/32
PersistentKeepalive = 25


# =============================================================================
# PEER : Serveur Marseille (tunnel P2P direct)
# =============================================================================
[Peer]
PublicKey = <CLE_PUBLIQUE_MRS>
Endpoint  = <IP_PUBLIQUE_MRS>:51820

#   10.0.0.2/32   → IP WireGuard de MRS (sauvegardes)
#   10.0.0.20/32  → client mrs-exitnode (symétrie mesh)
#   10.0.0.41/32  → client private-only entré via MRS
# Pas de 192.168.1.0/24 : Albi ne route jamais vers le LAN de Marseille.
AllowedIPs          = 10.0.0.2/32, 10.0.0.20/32, 10.0.0.41/32
PersistentKeepalive = 25


# =============================================================================
# PEER : Client albi-exitnode (IP publique = Albi, accès LAN Albi)
# =============================================================================
[Peer]
PublicKey  = <CLE_PUBLIQUE_CLIENT_ALBI>
AllowedIPs = 10.0.0.30/32


# =============================================================================
# PEER : Client private-only entré via Albi
# =============================================================================
[Peer]
PublicKey  = <CLE_PUBLIQUE_CLIENT_PRIVATE_ALBI>
AllowedIPs = 10.0.0.42/32
```

# Configuration Clients

#### Client Mesh

```ini
# =============================================================================
# Profil client — Réseau privé mesh uniquement (private-only)
# IP publique vue : INCHANGÉE (la propre connexion du client)
# Accès LAN : AUCUN (ni Marseille ni Albi)
# =============================================================================
#
# USAGE :
#   - Accès aux serveurs du mesh uniquement :
#       http://10.0.0.1:9000  → Portainer UI
#       ssh user@10.0.0.1 / .2 / .3  → SSH sur chaque serveur
#   - Internet du client : passe par sa connexion normale (pas d'exit node)
#   - 192.168.1.x / 192.168.2.x : INACCESSIBLES (UFW DROP côté serveurs)
#
# -----------------------------------------------------------------------------
# CHOIX DU POINT D'ENTRÉE
# -----------------------------------------------------------------------------
# Ce fichier ci-dessous est configuré pour entrer par OVH (cas par défaut).
# Pour entrer par un AUTRE serveur, 3 valeurs changent : Address, PublicKey
# du peer, et Endpoint. AllowedIPs reste TOUJOURS 10.0.0.0/24.
#
# IMPORTANT : chaque point d'entrée utilise une IP mesh DIFFÉRENTE.
# C'est obligatoire pour le routage WireGuard (une IP ne peut être routée
# que par un seul peer par serveur). Générez une paire de clés par variante,
# ou réutilisez la même clé en changeant seulement l'Address selon l'entrée.
#
#   ┌─────────────┬──────────────┬───────────────────────────┬──────────────────────┐
#   │ Entrée par  │ Address       │ [Peer] PublicKey          │ [Peer] Endpoint        │
#   ├─────────────┼──────────────┼───────────────────────────┼──────────────────────┤
#   │ OVH         │ 10.0.0.40/32 │ <CLE_PUBLIQUE_OVH>        │ <IP_PUBLIQUE_OVH>:51820 │
#   │ Marseille   │ 10.0.0.41/32 │ <CLE_PUBLIQUE_MRS>       │ <IP_PUBLIQUE_MRS>:51820 │
#   │ Albi        │ 10.0.0.42/32 │ <CLE_PUBLIQUE_ALBI>      │ <IP_PUBLIQUE_ALBI>:51820│
#   └─────────────┴──────────────┴───────────────────────────┴──────────────────────┘
#
# Rappel côté serveur : la clé publique du client doit être déclarée dans
# le [Peer] correspondant du serveur d'entrée (10.0.0.40 sur OVH,
# 10.0.0.41 sur MRS, 10.0.0.42 sur Albi). C'est déjà prévu dans les
# fichiers serveurs v3.
# =============================================================================

[Interface]
# ---- Entrée OVH (défaut) : 10.0.0.40/32 ----
# ---- Entrée MRS          : 10.0.0.41/32 ----
# ---- Entrée Albi         : 10.0.0.42/32 ----
Address    = 10.0.0.40/32
PrivateKey = <CLE_PRIVEE_CLIENT_PRIVATE>
# Pas de redirection DNS — on garde le DNS habituel du client.
# DNS = 10.0.0.1   ← décommenter si un DNS est déployé dans le mesh

[Peer]
# ---- Entrée OVH (défaut) ----
PublicKey = <CLE_PUBLIQUE_OVH>
Endpoint  = <IP_PUBLIQUE_OVH>:51820
#
# ---- Entrée MRS : remplacer les 2 lignes ci-dessus par ----
# PublicKey = <CLE_PUBLIQUE_MRS>
# Endpoint  = <IP_PUBLIQUE_MRS>:51820
#
# ---- Entrée Albi : remplacer les 2 lignes ci-dessus par ----
# PublicKey = <CLE_PUBLIQUE_ALBI>
# Endpoint  = <IP_PUBLIQUE_ALBI>:51820

# AllowedIPs : identique quel que soit le point d'entrée.
# Seul le mesh, aucun LAN, aucun exit node.
AllowedIPs          = 10.0.0.0/24
PersistentKeepalive = 25
```

#### Client Exit Node OVH

```ini
# =============================================================================
# Profil client — Exit node OVH
# Fichier : ovh-exitnode.conf   |   IP mesh : 10.0.0.10/32
# IP publique vue : VPS OVH     |   Accès LAN : aucun
# =============================================================================
#
# USAGE :
#   - Tout le trafic internet sort par OVH (IP publique = OVH)
#   - Accès au mesh (Portainer UI sur http://10.0.0.1:9000)
#   - 192.168.1.x et 192.168.2.x INACCESSIBLES (non routés + UFW DROP)
#
# =============================================================================

[Interface]
Address    = 10.0.0.10/32
PrivateKey = <CLE_PRIVEE_CLIENT_OVH>
DNS        = 1.1.1.1, 8.8.8.8

[Peer]
PublicKey           = <CLE_PUBLIQUE_OVH>
Endpoint            = <IP_PUBLIQUE_OVH>:51820
AllowedIPs          = 0.0.0.0/0, ::/0
PersistentKeepalive = 25
```

#### Client Exit Node Mrs + LAN

```ini
# =============================================================================
# Profil client — Exit node Marseille
# Fichier : mrs-exitnode.conf   |   IP mesh : 10.0.0.20/32
# IP publique vue : box Marseille  |  Accès LAN : 192.168.1.0/24 (LAN MRS)
# =============================================================================
#
# USAGE :
#   - Tout le trafic internet sort par Marseille (IP = box MRS)
#   - Accès complet au LAN de Marseille (NAS, caméras, IoT…)
#   - Accès au mesh (Portainer UI sur http://10.0.0.1:9000)
#   - 192.168.2.x (LAN Albi) INACCESSIBLE
#
# CONNEXION : directe vers Marseille (pas de transit par OVH).
#
# =============================================================================

[Interface]
Address    = 10.0.0.20/32
PrivateKey = <CLE_PRIVEE_CLIENT_MRS>
# DNS local de Marseille en priorité (résolution des noms du LAN), public en secours
DNS        = 192.168.1.53, 1.1.1.1

[Peer]
PublicKey           = <CLE_PUBLIQUE_MRS>
Endpoint            = <IP_PUBLIQUE_MRS>:51820
# 0.0.0.0/0 : tout passe par Marseille. Le LAN 192.168.1.0/24 est inclus
# dedans et son accès est autorisé côté serveur par UFW (uniquement pour
# cette IP 10.0.0.20). L'accès au LAN d'Albi reste bloqué (pas de route MRS
# vers 192.168.2.0/24 + UFW DROP côté Albi).
AllowedIPs          = 0.0.0.0/0, ::/0
PersistentKeepalive = 25
```

#### Client Exit Node Albi + LAN

```ini
# =============================================================================
# Profil client — Exit node Albi
# Fichier : albi-exitnode.conf   |   IP mesh : 10.0.0.30/32
# IP publique vue : box Albi      |  Accès LAN : 192.168.2.0/24 (LAN Albi)
# =============================================================================
#
# USAGE :
#   - Tout le trafic internet sort par Albi (IP = box Albi)
#   - Accès complet au LAN d'Albi (NAS, caméras Frigate, IoT…)
#   - Accès au mesh (Portainer UI sur http://10.0.0.1:9000)
#   - 192.168.1.x (LAN Marseille) INACCESSIBLE
#
# CONNEXION : directe vers Albi (pas de transit par OVH).
#
# =============================================================================

[Interface]
Address    = 10.0.0.30/32
PrivateKey = <CLE_PRIVEE_CLIENT_ALBI>
DNS        = 192.168.2.53, 1.1.1.1

[Peer]
PublicKey           = <CLE_PUBLIQUE_ALBI>
Endpoint            = <IP_PUBLIQUE_ALBI>:51820
AllowedIPs          = 0.0.0.0/0, ::/0
PersistentKeepalive = 25
```

# Configuration Pare-feu

#### Par-feu OVH

```bash
#!/usr/bin/env bash
# =============================================================================
# Configuration UFW — VPS OVH
# Interface physique : eth0   |   IP WireGuard : 10.0.0.1
# =============================================================================
#
# À exécuter en root APRÈS avoir démarré le conteneur WireGuard (wg0 doit exister).
#   sudo bash ovh-ufw-setup.sh
#
# Ce script :
#   1. Active le forwarding IP au niveau hôte
#   2. Ajoute le masquerading (NAT) pour les clients exit-node OVH
#   3. Pose une politique FORWARD = DROP et n'autorise que le trafic VPN voulu
#   4. Ouvre les ports nécessaires (tunnel, SSH, Portainer UI sur le mesh)
#
# IMPORTANT : ne casse PAS Docker. UFW pose FORWARD à DROP, ce que Docker
# fait déjà de son côté ; Docker gère ses propres règles ACCEPT via
# DOCKER-USER. La communication entre conteneurs reste fonctionnelle.
# =============================================================================
set -euo pipefail

IFACE_PHYS="eth0"
WG_IFACE="wg0"
MESH="10.0.0.0/24"

echo "[1/5] Activation du forwarding IP (hôte)"
# net/ipv4 syntaxe attendue par /etc/ufw/sysctl.conf
grep -q "net/ipv4/ip_forward=1" /etc/ufw/sysctl.conf || \
  echo "net/ipv4/ip_forward=1" >> /etc/ufw/sysctl.conf
grep -q "net/ipv6/conf/all/forwarding=1" /etc/ufw/sysctl.conf || \
  echo "net/ipv6/conf/all/forwarding=1" >> /etc/ufw/sysctl.conf
# src_valid_mark requis par wg-quick (routage marqué)
echo "net.ipv4.conf.all.src_valid_mark=1" > /etc/sysctl.d/99-wireguard.conf
sysctl -p /etc/sysctl.d/99-wireguard.conf >/dev/null

echo "[2/5] Politique FORWARD par défaut = DROP"
sed -i 's/^DEFAULT_FORWARD_POLICY=.*/DEFAULT_FORWARD_POLICY="DROP"/' /etc/default/ufw

echo "[3/5] Masquerading NAT dans before.rules"
# On insère un bloc *nat en tête de /etc/ufw/before.rules s'il n'y est pas déjà.
if ! grep -q "WG-MASQUERADE-OVH" /etc/ufw/before.rules; then
  cp /etc/ufw/before.rules /etc/ufw/before.rules.bak.$(date +%s)
  cat > /tmp/wg-nat.rules <<EOF
# WG-MASQUERADE-OVH (ne pas supprimer cette ligne, sert de marqueur)
*nat
:POSTROUTING ACCEPT [0:0]
# Le trafic des clients VPN qui sort par eth0 prend l'IP publique d'OVH
-A POSTROUTING -s ${MESH} -o ${IFACE_PHYS} -j MASQUERADE
COMMIT

EOF
  # Préfixe le fichier existant avec le bloc nat
  cat /tmp/wg-nat.rules /etc/ufw/before.rules > /tmp/before.rules.new
  mv /tmp/before.rules.new /etc/ufw/before.rules
  rm -f /tmp/wg-nat.rules
fi

echo "[4/5] Ports d'entrée (INPUT)"
ufw allow OpenSSH                                   # ne pas se verrouiller dehors
ufw allow 51820/udp comment 'WireGuard tunnel'
# Portainer UI : accessible UNIQUEMENT via le mesh (interface wg0)
ufw allow in on ${WG_IFACE} to any port 9000 proto tcp comment 'Portainer UI (mesh)'
# SSH via le mesh (administration interne)
ufw allow in on ${WG_IFACE} to any port 22 proto tcp comment 'SSH mesh'

echo "[5/5] Règles de routage VPN (FORWARD)"
# --- Client ovh-exitnode (10.0.0.10) ---
# Sortie internet par OVH
ufw route allow in on ${WG_IFACE} out on ${IFACE_PHYS} from 10.0.0.10 comment 'ovh-exitnode internet'
# Accès au reste du mesh (relais vers MRS/Albi)
ufw route allow in on ${WG_IFACE} out on ${WG_IFACE} from 10.0.0.10 to ${MESH} comment 'ovh-exitnode mesh'
# --- Client private-only entré via OVH (10.0.0.40) ---
# Mesh uniquement, AUCUNE sortie eth0 (pas d'internet, pas de LAN)
ufw route allow in on ${WG_IFACE} out on ${WG_IFACE} from 10.0.0.40 to ${MESH} comment 'private-only-ovh mesh'

echo "Activation/rechargement d'UFW"
ufw --force enable
ufw reload

echo
echo "=== Terminé. Vérifs utiles : ==="
echo "  ufw status verbose"
echo "  ufw route status"
echo "  iptables -t nat -L POSTROUTING -n | grep MASQUERADE"
echo
echo "Si les conteneurs Docker perdent le réseau, redémarrez Docker UNE fois"
echo "pour qu'il réinsère ses règles au-dessus de celles d'UFW :"
echo "  systemctl restart docker"

```

#### Par-feu Marseille

```bash
#!/usr/bin/env bash
# =============================================================================
# Configuration UFW — Serveur Marseille
# Interface physique : enp4s0   |   IP WireGuard : 10.0.0.2
# LAN local : 192.168.1.0/24
# =============================================================================
#
#   sudo bash marseille-ufw-setup.sh
#
# Accès LAN Marseille (192.168.1.0/24) autorisé UNIQUEMENT au client
# mrs-exitnode (10.0.0.20). Tout autre peer est bloqué par le FORWARD DROP.
# Aucune route statique sur la box n'est nécessaire (masquerading sur enp4s0).
# =============================================================================
set -euo pipefail

IFACE_PHYS="enp4s0"
WG_IFACE="wg0"
MESH="10.0.0.0/24"
LAN="192.168.1.0/24"

echo "[1/5] Forwarding IP (hôte)"
grep -q "net/ipv4/ip_forward=1" /etc/ufw/sysctl.conf || \
  echo "net/ipv4/ip_forward=1" >> /etc/ufw/sysctl.conf
grep -q "net/ipv6/conf/all/forwarding=1" /etc/ufw/sysctl.conf || \
  echo "net/ipv6/conf/all/forwarding=1" >> /etc/ufw/sysctl.conf
echo "net.ipv4.conf.all.src_valid_mark=1" > /etc/sysctl.d/99-wireguard.conf
sysctl -p /etc/sysctl.d/99-wireguard.conf >/dev/null

echo "[2/5] Politique FORWARD = DROP"
sed -i 's/^DEFAULT_FORWARD_POLICY=.*/DEFAULT_FORWARD_POLICY="DROP"/' /etc/default/ufw

echo "[3/5] Masquerading NAT (enp4s0)"
if ! grep -q "WG-MASQUERADE-MRS" /etc/ufw/before.rules; then
  cp /etc/ufw/before.rules /etc/ufw/before.rules.bak.$(date +%s)
  cat > /tmp/wg-nat.rules <<EOF
# WG-MASQUERADE-MRS (marqueur — ne pas supprimer)
*nat
:POSTROUTING ACCEPT [0:0]
# Couvre l'exit node (internet) ET l'accès au LAN : dans les deux cas le
# trafic sort par enp4s0 et prend l'IP locale du serveur (ex 192.168.1.100),
# ce qui évite toute route statique sur la box.
-A POSTROUTING -s ${MESH} -o ${IFACE_PHYS} -j MASQUERADE
COMMIT

EOF
  cat /tmp/wg-nat.rules /etc/ufw/before.rules > /tmp/before.rules.new
  mv /tmp/before.rules.new /etc/ufw/before.rules
  rm -f /tmp/wg-nat.rules
fi

echo "[4/5] Ports d'entrée (INPUT)"
ufw allow OpenSSH
ufw allow 51820/udp comment 'WireGuard tunnel'
# Portainer Agent : joignable uniquement par Portainer UI via le mesh
ufw allow in on ${WG_IFACE} to any port 9001 proto tcp comment 'Portainer Agent (mesh)'
# SSH via mesh — sert aussi aux sauvegardes rsync depuis Albi
ufw allow in on ${WG_IFACE} to any port 22 proto tcp comment 'SSH mesh / backups'

echo "[5/5] Règles de routage VPN (FORWARD)"
# --- Client mrs-exitnode (10.0.0.20) : internet + LAN Marseille ---
ufw route allow in on ${WG_IFACE} out on ${IFACE_PHYS} from 10.0.0.20 comment 'mrs-exitnode internet+LAN'
ufw route allow in on ${WG_IFACE} out on ${WG_IFACE} from 10.0.0.20 to ${MESH} comment 'mrs-exitnode mesh'
# --- Client private-only entré via MRS (10.0.0.41) : mesh uniquement ---
# Pas de règle "out on enp4s0" => ni internet ni LAN pour ce client.
ufw route allow in on ${WG_IFACE} out on ${WG_IFACE} from 10.0.0.41 to ${MESH} comment 'private-only-mrs mesh'

echo "Activation/rechargement d'UFW"
ufw --force enable
ufw reload

echo
echo "=== Terminé. Vérifs : ufw status verbose ; ufw route status ==="
echo "Test attendu :"
echo "  - mrs-exitnode atteint 192.168.1.x : OUI"
echo "  - private-only / autres profils atteignent 192.168.1.x : NON"
echo
echo "Si Docker perd le réseau : systemctl restart docker (une fois)"

```

#### Par-feu Albi

```bash
#!/usr/bin/env bash
# =============================================================================
# Configuration UFW — Serveur Albi
# Interface physique : enp2s0   |   IP WireGuard : 10.0.0.3
# LAN local : 192.168.2.0/24
# =============================================================================
#
#   sudo bash albi-ufw-setup.sh
#
# Accès LAN Albi (192.168.2.0/24) autorisé UNIQUEMENT au client
# albi-exitnode (10.0.0.30).
#
# COHABITATION DOCKER : Home Assistant et Frigate ne sont pas affectés.
# Leur trafic est local (OUTPUT/INPUT) ou géré par Docker, pas par la
# chaîne FORWARD qu'on filtre ici. Voir la note Docker en fin de script.
# =============================================================================
set -euo pipefail

IFACE_PHYS="enp2s0"
WG_IFACE="wg0"
MESH="10.0.0.0/24"
LAN="192.168.2.0/24"

echo "[1/5] Forwarding IP (hôte)"
grep -q "net/ipv4/ip_forward=1" /etc/ufw/sysctl.conf || \
  echo "net/ipv4/ip_forward=1" >> /etc/ufw/sysctl.conf
grep -q "net/ipv6/conf/all/forwarding=1" /etc/ufw/sysctl.conf || \
  echo "net/ipv6/conf/all/forwarding=1" >> /etc/ufw/sysctl.conf
echo "net.ipv4.conf.all.src_valid_mark=1" > /etc/sysctl.d/99-wireguard.conf
sysctl -p /etc/sysctl.d/99-wireguard.conf >/dev/null

echo "[2/5] Politique FORWARD = DROP"
sed -i 's/^DEFAULT_FORWARD_POLICY=.*/DEFAULT_FORWARD_POLICY="DROP"/' /etc/default/ufw

echo "[3/5] Masquerading NAT (enp2s0)"
if ! grep -q "WG-MASQUERADE-ALBI" /etc/ufw/before.rules; then
  cp /etc/ufw/before.rules /etc/ufw/before.rules.bak.$(date +%s)
  cat > /tmp/wg-nat.rules <<EOF
# WG-MASQUERADE-ALBI (marqueur — ne pas supprimer)
*nat
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -s ${MESH} -o ${IFACE_PHYS} -j MASQUERADE
COMMIT

EOF
  cat /tmp/wg-nat.rules /etc/ufw/before.rules > /tmp/before.rules.new
  mv /tmp/before.rules.new /etc/ufw/before.rules
  rm -f /tmp/wg-nat.rules
fi

echo "[4/5] Ports d'entrée (INPUT)"
ufw allow OpenSSH
ufw allow 51820/udp comment 'WireGuard tunnel'
ufw allow in on ${WG_IFACE} to any port 9001 proto tcp comment 'Portainer Agent (mesh)'
ufw allow in on ${WG_IFACE} to any port 22 proto tcp comment 'SSH mesh / backups'

echo "[5/5] Règles de routage VPN (FORWARD)"
# --- Client albi-exitnode (10.0.0.30) : internet + LAN Albi ---
ufw route allow in on ${WG_IFACE} out on ${IFACE_PHYS} from 10.0.0.30 comment 'albi-exitnode internet+LAN'
ufw route allow in on ${WG_IFACE} out on ${WG_IFACE} from 10.0.0.30 to ${MESH} comment 'albi-exitnode mesh'
# --- Client private-only entré via Albi (10.0.0.42) : mesh uniquement ---
ufw route allow in on ${WG_IFACE} out on ${WG_IFACE} from 10.0.0.42 to ${MESH} comment 'private-only-albi mesh'

echo "Activation/rechargement d'UFW"
ufw --force enable
ufw reload

echo
echo "=== Terminé. ==="
echo "NOTE DOCKER (Home Assistant / Frigate) :"
echo "  Si après activation d'UFW les conteneurs perdent l'accès réseau,"
echo "  redémarrez Docker UNE fois pour qu'il réinsère ses règles FORWARD"
echo "  au-dessus de celles d'UFW :"
echo "    systemctl restart docker"
echo "  (cela redémarre Home Assistant et Frigate — à faire à un moment calme)"

```