---
title: "WireGuard — VPN moderne"
domain: network
subdomain: vpn
type: snippet
tags: [wireguard, vpn, linux, tunnel, peer, wg, split-tunnel]
difficulty: intermediate
status: stable
updated: "2025-05-14"
---
## Concepts

```
WireGuard = VPN moderne, minimaliste, haute performance (kernel module depuis Linux 5.6)
Protocole : UDP uniquement (port 51820 par défaut)
Cryptographie : Curve25519 (ECDH), ChaCha20, Poly1305, BLAKE2s — pas de négociation
Modèle : peer-to-peer (pas de notion serveur/client stricte au niveau protocolaire)
Clés : chaque interface a une paire clé privée/publique (asymétrique)

Avantages vs IPsec/OpenVPN :
  - Configuration ultra-simple (~50 lignes de config)
  - Performances supérieures (code kernel minimal)
  - Roaming natif (le tunnel suit l'IP du client)
  - Pas de certificates/CA à gérer (PSK par défaut)

Limitation :
  - UDP uniquement → peut être bloqué par certains firewalls
  - Pas de NAT traversal automatique → PersistentKeepalive requis derrière NAT
  - Logs minimes (pas d'audit trail natif)
```

## Installation

```bash
# Debian/Ubuntu (kernel 5.6+ inclut WireGuard nativement)
apt update && apt install wireguard wireguard-tools

# RHEL/CentOS/Rocky 8+
dnf install epel-release
dnf install wireguard-tools

# Arch Linux
pacman -S wireguard-tools

# Vérifier le module kernel
lsmod | grep wireguard
modprobe wireguard
```

## Génération des clés

```bash
# Méthode recommandée — générer clé privée + publique en une commande
wg genkey | tee /etc/wireguard/server_private.key | wg pubkey > /etc/wireguard/server_public.key

# Afficher les clés
cat /etc/wireguard/server_private.key    # GARDÉE SECRÈTE
cat /etc/wireguard/server_public.key     # distribuée aux clients

# Protéger les permissions
chmod 600 /etc/wireguard/server_private.key
chmod 600 /etc/wireguard/

# Pour chaque client
wg genkey | tee /etc/wireguard/client1_private.key | wg pubkey > /etc/wireguard/client1_public.key

# Preshared Key (optionnel — couche de sécurité supplémentaire par peer)
wg genpsk > /etc/wireguard/client1_psk.key
```

## Configuration serveur — /etc/wireguard/wg0.conf

```bash
# /etc/wireguard/wg0.conf
[Interface]
# Adresse IP du serveur dans le tunnel VPN
Address = {{VPN_SERVER_IP}}/24

# Port d'écoute UDP
ListenPort = 51820

# Clé privée du serveur
PrivateKey = {{SERVER_PRIVATE_KEY}}

# DNS (optionnel — pour les clients full-tunnel)
# DNS = {{DNS_IP}}

# NAT : permettre aux clients VPN d'accéder à Internet via le serveur
# Remplacer eth0 par l'interface WAN réelle
PostUp   = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

# ── Client 1 ──────────────────────────────────────────────
[Peer]
# Clé publique du client
PublicKey = {{CLIENT1_PUBLIC_KEY}}

# Preshared key (optionnel mais recommandé)
PresharedKey = {{CLIENT1_PSK}}

# IP autorisée pour ce peer dans le VPN
AllowedIPs = {{VPN_CLIENT1_IP}}/32

# ── Client 2 ──────────────────────────────────────────────
[Peer]
PublicKey = {{CLIENT2_PUBLIC_KEY}}
PresharedKey = {{CLIENT2_PSK}}
AllowedIPs = {{VPN_CLIENT2_IP}}/32

# ── Site-to-Site (LAN distant) ────────────────────────────
[Peer]
PublicKey = {{SITE_B_PUBLIC_KEY}}
# AllowedIPs inclut le LAN distant complet
AllowedIPs = {{VPN_SITE_B_IP}}/32, {{SITE_B_LAN}}/{{SITE_B_PREFIX}}
Endpoint = {{SITE_B_WAN_IP}}:51820
PersistentKeepalive = 25
```

## Configuration client — Full Tunnel (tout le trafic via VPN)

```bash
# /etc/wireguard/wg0.conf sur le client
[Interface]
Address = {{VPN_CLIENT_IP}}/32
PrivateKey = {{CLIENT_PRIVATE_KEY}}
DNS = {{DNS_IP}}                          # optionnel — évite les DNS leaks

[Peer]
PublicKey = {{SERVER_PUBLIC_KEY}}
PresharedKey = {{CLIENT_PSK}}
Endpoint = {{SERVER_WAN_IP}}:51820

# Full tunnel : TOUT le trafic passe par le VPN
AllowedIPs = 0.0.0.0/0, ::/0

# OBLIGATOIRE si le client est derrière NAT (box domestique, 4G...)
PersistentKeepalive = 25
```

## Configuration client — Split Tunnel (uniquement le réseau privé)

```bash
# /etc/wireguard/wg0.conf
[Interface]
Address = {{VPN_CLIENT_IP}}/32
PrivateKey = {{CLIENT_PRIVATE_KEY}}

[Peer]
PublicKey = {{SERVER_PUBLIC_KEY}}
Endpoint = {{SERVER_WAN_IP}}:51820

# Split tunnel : seul le trafic vers les réseaux privés passe par le VPN
AllowedIPs = {{CORP_LAN_1}}/{{PREFIX_1}}, {{CORP_LAN_2}}/{{PREFIX_2}}, {{VPN_SUBNET}}/24

PersistentKeepalive = 25
```

## Démarrage et activation

```bash
# Activer l'IP forwarding sur le serveur (persistant)
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
echo "net.ipv6.conf.all.forwarding = 1" >> /etc/sysctl.conf
sysctl -p

# Démarrer l'interface manuellement
wg-quick up wg0

# Arrêter l'interface
wg-quick down wg0

# Activer au démarrage (systemd)
systemctl enable wg-quick@wg0
systemctl start wg-quick@wg0
systemctl status wg-quick@wg0

# Restart après modification de config
wg-quick down wg0 && wg-quick up wg0
# OU (recharge sans couper les connexions existantes)
wg syncconf wg0 <(wg-quick strip wg0)
```

## Gestion dynamique des peers

```bash
# Ajouter un peer à chaud (sans restart)
wg set wg0 peer {{CLIENT_PUBLIC_KEY}} allowed-ips {{VPN_CLIENT_IP}}/32

# Ajouter avec endpoint et keepalive
wg set wg0 peer {{CLIENT_PUBLIC_KEY}} \
    allowed-ips {{VPN_CLIENT_IP}}/32 \
    endpoint {{CLIENT_WAN_IP}}:51820 \
    persistent-keepalive 25

# Supprimer un peer
wg set wg0 peer {{CLIENT_PUBLIC_KEY}} remove

# Sauvegarder la config actuelle (inclut les peers ajoutés dynamiquement)
wg showconf wg0 > /etc/wireguard/wg0.conf
```

## Vérifications

```bash
# État de toutes les interfaces WireGuard
wg show

# Exemple de sortie :
# interface: wg0
#   public key: abc123...
#   private key: (hidden)
#   listening port: 51820
#
# peer: xyz789...
#   endpoint: 203.0.113.5:51820
#   allowed ips: 10.0.0.2/32
#   latest handshake: 1 minute, 30 seconds ago
#   transfer: 1.23 MiB received, 456 KiB sent

# Configuration complète (avec clé privée en clair — attention)
wg showconf wg0

# Interface réseau
ip addr show wg0
ip route show dev wg0

# Vérifier la connectivité VPN
ping {{VPN_SERVER_IP}}
ping {{VPN_CLIENT_IP}}

# Tracer le chemin
traceroute {{CORP_HOST}}
```

## DNS Leak Prevention

```bash
# Dans la config client, utiliser DNS du serveur VPN
[Interface]
DNS = {{VPN_DNS_IP}}

# Sur le serveur VPN — Pi-hole ou Unbound local
# Vérifier les leaks sur : https://dnsleaktest.com

# Pour IPv6 — désactiver si non utilisé (évite les leaks IPv6)
[Interface]
PreUp = ip6tables -A OUTPUT -o {{WAN_IFACE}} -j DROP   # bloquer IPv6 sortant hors VPN
```

## Génération QR code (mobile)

```bash
# Générer un QR code pour importer la config sur mobile
apt install qrencode

# Depuis un fichier config client
qrencode -t ansiutf8 < /etc/wireguard/client1.conf

# Afficher dans le terminal
qrencode -t UTF8 < /etc/wireguard/client1.conf
```

## Exemple script — Générer un nouveau client

```bash
#!/bin/bash
CLIENT_NAME=$1
VPN_CLIENT_IP=$2       # ex: 10.8.0.X
WG_SERVER_CONF="/etc/wireguard/wg0.conf"

# Générer les clés client
CLIENT_PRIV=$(wg genkey)
CLIENT_PUB=$(echo "$CLIENT_PRIV" | wg pubkey)
CLIENT_PSK=$(wg genpsk)

# Afficher la config client
cat <<EOF
[Interface]
PrivateKey = $CLIENT_PRIV
Address = $VPN_CLIENT_IP/32
DNS = {{VPN_DNS_IP}}

[Peer]
PublicKey = $(cat /etc/wireguard/server_public.key)
PresharedKey = $CLIENT_PSK
Endpoint = {{SERVER_WAN_IP}}:51820
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25
EOF

# Ajouter le peer côté serveur
wg set wg0 peer "$CLIENT_PUB" preshared-key <(echo "$CLIENT_PSK") allowed-ips "$VPN_CLIENT_IP/32"
echo "" >> $WG_SERVER_CONF
echo "[Peer]  # $CLIENT_NAME" >> $WG_SERVER_CONF
echo "PublicKey = $CLIENT_PUB" >> $WG_SERVER_CONF
echo "PresharedKey = $CLIENT_PSK" >> $WG_SERVER_CONF
echo "AllowedIPs = $VPN_CLIENT_IP/32" >> $WG_SERVER_CONF
```

<Tip>
WireGuard ne maintient pas de connexion persistante — il n'envoie des paquets que lorsqu'il y a du trafic. Un client derrière NAT (box domestique, 4G, etc.) verra son mappage NAT expirer après quelques dizaines de secondes d'inactivité, rendant le tunnel injoignable depuis le serveur. Configurer `PersistentKeepalive = 25` sur le client envoie un paquet keepalive UDP toutes les 25 secondes pour maintenir le mappage NAT actif.
</Tip>
