Intermediaire 9 min de lecture · 1 809 mots

WireGuard vs Tailscale : quel VPN pour accéder à ton homelab depuis l’extérieur ?

Depuis un hôtel en déplacement, j’ai voulu me connecter à l’interface Proxmox de heighliner pour vérifier l’état d’un déploiement. Ma première réaction a été d’ouvrir le port 8006 directement sur la box. J’ai tenu 30 secondes avant de refermer ce menu. Exposer Proxmox sur Internet sans VPN, c’est non. Il fallait un tunnel.

Le problème concret

Mon accès Internet à la maison est une fibre Orange avec une IP publique dynamique. Pas de CGNAT, ce qui simplifie les choses pour WireGuard, mais l’IP change à chaque redémarrage de la box ZenWifi XT8. Le homelab tourne sur heighliner (MS-01 i9-13900H, Proxmox VE 8.3), avec des services répartis sur des LXC dans plusieurs VLANs. Ce que je veux depuis l’extérieur : accéder à Proxmox (VLAN Management, 10.10.1.0/24), à Nextcloud, Gitea, et l’UI ArgoCD (VLAN Serveurs, 10.10.30.0/24), et au dashboard Pi-hole (VLAN IoT, 10.10.20.0/24). Soit l’ensemble du réseau 10.10.0.0/16.

J’ai testé les deux solutions séquentiellement, sur la même infrastructure, avant de trancher.

WireGuard : protocole nu, config manuelle

WireGuard est un protocole VPN UDP intégré au kernel Linux depuis 5.6. Il est très rapide, minimaliste, et ne transporte que ce que tu lui demandes explicitement. Pas de discovery automatique, pas de gestion des pairs dynamique : tu listes manuellement chaque pair avec sa clé publique et ses AllowedIPs. C’est sa force et son inconvénient principal.

Installation du serveur sur LXC 110

J’ai dédié un LXC Debian 12 (ID 110) au rôle de passerelle VPN. IP interne : 10.10.30.110, sur le VLAN Serveurs. Sur la box ZenWifi XT8, une règle NAT redirige le port 51820/UDP vers cette IP.

Ouvrir un port entrant sur ta box expose cette IP au réseau public. Vérifie que le firewall du LXC 110 n’accepte que le port 51820/UDP en entrée depuis Internet, et limite le SSH à ton réseau interne.

sudo apt-get install -y wireguard
wg genkey | tee /etc/wireguard/server_private.key | wg pubkey > /etc/wireguard/server_public.key
chmod 600 /etc/wireguard/server_private.key

Configuration /etc/wireguard/wg0.conf côté serveur :

[Interface]
PrivateKey = 
Address = 10.200.0.1/24
ListenPort = 51820
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -o wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

[Peer]
PublicKey = 
AllowedIPs = 10.200.0.2/32

[Peer]
# Téléphone Android
PublicKey = 
AllowedIPs = 10.200.0.3/32

Le sous-réseau 10.200.0.0/24 est le réseau WireGuard. Le serveur y est .1, les clients .2 et .3. Les règles iptables en PostUp activent le forwarding du trafic des clients vers le réseau interne – indispensable pour atteindre le reste du homelab.

Activer le forwarding IP sur le LXC 110 :

echo "net.ipv4.ip_forward = 1" | sudo tee /etc/sysctl.d/99-wg.conf
sudo sysctl --system
sudo systemctl enable --now wg-quick@wg0

Configuration du client laptop (Linux)

Même mécanique côté client – on génère une paire de clés, on monte le fichier de config :

[Interface]
PrivateKey = 
Address = 10.200.0.2/24
DNS = 10.10.20.5

[Peer]
PublicKey = 
Endpoint = mon-homelab.duckdns.org:51820
AllowedIPs = 10.10.0.0/16, 10.200.0.0/24
PersistentKeepalive = 25

AllowedIPs = 10.10.0.0/16 route tout le trafic homelab dans le tunnel, sans router le reste d’Internet par là (split tunnel). DNS = 10.10.20.5 pointe vers Pi-hole pour résoudre les noms internes.

DNS dynamique avec DuckDNS

L’IP publique Orange change. Sans DNS dynamique, le client ne sait plus où pointer l’Endpoint. J’ai configuré DuckDNS (gratuit, subdomaine mon-homelab.duckdns.org) avec un cron sur heighliner qui met à jour l’IP toutes les 5 minutes :

*/5 * * * * curl -sf "https://www.duckdns.org/update?domains=mon-homelab&token=&ip=" > /dev/null

Client Android

WireGuard a une application Android officielle. Plutôt que de saisir la config à la main, j’ai généré un QR code depuis le serveur :

sudo apt-get install -y qrencode
wg showconf wg0 | grep -A5 '[Peer]'  # Pour vérifier la config du peer Android
# Générer le QR depuis le fichier de config client
qrencode -t ansiutf8 < /etc/wireguard/wg0-android.conf

L'appli scanne le QR et importe la configuration complète. La connexion s'établit en moins de 2 secondes depuis un réseau 4G.

Performances mesurées (WireGuard)

Benchmark iperf3 entre mon laptop et le LXC 110, depuis le même réseau local (meilleur cas théorique, pour estimer le plafond du protocole) :

# Sur le LXC 110 (serveur iperf3)
iperf3 -s

# Sur le laptop client
iperf3 -c 10.200.0.1 -t 30

Résultat : 850 Mbps montant, 840 Mbps descendant. Le NVMe et la RAM DDR5 de heighliner ne sont pas le goulot d'étranglement ici - c'est la crypto WireGuard sur le CPU du LXC qui commence à saturer vers 900 Mbps. En pratique depuis Internet, le débit réel est limité par la montante fibre (1 Gbps théorique, environ 920 Mbps mesurés par mon FAI). WireGuard ne bride rien.

Ce qui fatigue avec WireGuard nu

Après deux mois d'utilisation, le problème n'est pas technique. C'est opérationnel. Ajouter un nouveau device (tablette, machine d'un ami pour dépanner quelque chose) demande de générer manuellement une paire de clés, d'éditer wg0.conf sur le serveur, de relancer wg syncconf ou de redémarrer l'interface, et de distribuer la config client. Avec 2 devices c'est gérable. Avec 5 ou 6, ça devient une corvée. Et si l'IP publique bascule pendant que je suis en déplacement, je dois attendre que DuckDNS se mette à jour avant de pouvoir reconnecter.

Tailscale : la même chose, sans la config manuelle

Tailscale est une surcouche WireGuard. Il gère l'échange de clés, la discovery des pairs, le NAT traversal (DERP relays si le peer-to-peer direct échoue), et expose un DNS magique. Le plan gratuit couvre 100 devices - amplement suffisant pour un homelab.

Installation sur heighliner

curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up

Authentification via le navigateur (lien imprimé dans le terminal). heighliner apparaît dans la console Tailscale sous son hostname. C'est tout pour la connectivité de base entre devices Tailscale.

Subnet router : exposer tout le homelab

Sans subnet router, seul heighliner lui-même est joignable via Tailscale. Pour atteindre les LXC (Pi-hole sur 10.10.20.5, Gitea sur 10.10.30.104, etc.), il faut annoncer le réseau homelab :

sudo tailscale up --advertise-routes=10.10.0.0/16 --accept-dns=false

Dans la console Tailscale (admin.tailscale.com), on approuve les routes annoncées par heighliner. Sur les autres devices (laptop, mobile), on active l'acceptation de ces routes depuis l'app Tailscale. Après ça, depuis mon laptop en 4G, curl http://10.10.30.104 atteint directement Gitea via heighliner comme routeur.

Sur Linux, active aussi --accept-routes sur le client pour recevoir automatiquement les routes des subnet routers : tailscale up --accept-routes.

Magic DNS

Tailscale assigne un nom DNS à chaque device : heighliner.tail-xxxxx.ts.net. Mais ce qui m'intéresse, c'est de résoudre les noms de mes LXC. En configurant le split DNS dans la console Tailscale (section DNS), je peux pointer le suffixe homelab.local vers Pi-hole (10.10.20.5). Résultat : depuis n'importe quel client Tailscale, gitea.homelab.local se résout correctement.

Exit node

Pour les réseaux non fiables (hôtel, conférence), j'active heighliner comme exit node - tout le trafic Internet du client passe par heighliner :

# Sur heighliner
sudo tailscale up --advertise-routes=10.10.0.0/16 --advertise-exit-node

# Sur le client
tailscale up --exit-node=heighliner

Avec l'exit node actif, mon trafic sort par la fibre à domicile plutôt que par le WiFi de l'hôtel.

Headscale (mention)

Headscale est un serveur de coordination Tailscale auto-hébergé. Il remplace la partie cloud de Tailscale (gestion des clés, discovery) en le faisant tourner localement. Je l'ai testé brièvement mais pas mis en production - ça nécessite une IP publique permanente ou un VPS accessible, ce qui ajoute une dépendance externe pour une dépendance externe. Je reviendrai sur Headscale dans un article dédié si le besoin se précise.

Comparaison honnête

Tailscale fonctionne même derrière du CGNAT (Double NAT, fréquent chez certains opérateurs mobiles) grâce aux DERP relays. WireGuard nu nécessite un port ouvert entrant, donc une IP publique accessible - pas possible si ton FAI te met derrière du CGNAT. Sur Orange fibre, j'avais une IP publique, donc WireGuard fonctionnait. Mais ce n'est pas universel.

WireGuard nu te donne un contrôle complet et aucune dépendance à un service tiers. Si Tailscale ferme ou change ses tarifs, tu migres. Avec WireGuard pur, aucun tiers ne peut te couper l'accès. Tailscale garde quand même la connexion peer-to-peer directe entre les appareils une fois les clés échangées - le serveur de coordination Tailscale ne voit pas le trafic. Mais si la coordination devient inaccessible, les nouvelles connexions échouent.

En pratique, Tailscale me fait économiser 15 minutes à chaque ajout de device, et fonctionne depuis des réseaux où WireGuard avec DuckDNS mettait parfois plusieurs minutes à reconnecter après un changement d'IP publique.

Résultats mesurés (Tailscale)

Latence depuis mon téléphone en 4G (Bouygues) vers heighliner, accès à l'interface Nextcloud :

ping heighliner.tail-xxxxx.ts.net
64 bytes from 100.x.x.x: icmp_seq=1 ttl=64 time=43.2 ms
64 bytes from 100.x.x.x: icmp_seq=2 ttl=64 time=44.8 ms
64 bytes from 100.x.x.x: icmp_seq=3 ttl=64 time=43.9 ms

Débit descendant mesuré via speedtest-cli sur le téléphone avec exit node Tailscale activé : ~50 Mbps. C'est le plafond de la montante fibre à domicile (50 Mbps sur 1 Gbps symétrique - plan Orange Fibre standard). Tailscale lui-même n'introduit pas de goulot mesurable : sans exit node, depuis le même réseau 4G, le téléphone plafonne à 48 Mbps. La différence est dans le bruit de mesure.

Les connexions peer-to-peer directes (sans DERP relay) sont confirmées dans les logs Tailscale : [direct] apparaît dans tailscale status entre heighliner et les clients mobiles une fois le NAT traversal établi.

Ce que j'utilise maintenant

Tailscale. WireGuard nu était fonctionnel et je comprends mieux son fonctionnement interne grâce à l'avoir configuré à la main. Mais avec une demi-douzaine de devices à gérer, la friction opérationnelle de WireGuard nu ne valait plus le gain de contrôle. Le script DuckDNS en cron qui rate pendant un changement d'IP, les fichiers de config à synchroniser manuellement entre appareils, les oublis de wg syncconf après une modification : tout ça disparaît avec Tailscale.

La seule raison de revenir à WireGuard nu serait une exigence de zéro dépendance cloud, ou l'adoption de Headscale pour garder le contrôle de la coordination. Pour l'instant, Tailscale gratuit couvre largement le homelab.


slug: wireguard-vs-tailscale-homelab
meta: Comparaison WireGuard nu vs Tailscale pour l'accès distant au homelab : config, perf mesurées, CGNAT, et pourquoi je suis passé à Tailscale. (~155 chars)
tags: wireguard, tailscale, vpn, homelab, réseau, subnet-router, duckdns

Une remarque, un retour ?

Cet article est vivant - corrections, contre-arguments et retours de production sont les bienvenus. Trois canaux, choisissez celui qui vous convient.

Laisser un commentaire