Le problème : exposer un service derrière NAT
La plupart des connexions résidentielles ou d'entreprise placent vos machines derrière un NAT : aucun port entrant n'est joignable depuis l'extérieur sans configuration explicite sur le routeur. Et même quand cette configuration est possible, elle expose directement votre réseau local.
Les scénarios réels sont nombreux : un NAS Synology dont vous voulez partager Nextcloud avec des clients, un homelab sous Proxmox hébergeant une dizaine de services, un Raspberry Pi tournant en domotique, ou une VM locale de développement que vous souhaitez tester depuis l'extérieur. Dans tous ces cas, la solution habituelle — le port-forwarding — pose deux problèmes : elle dépend du routeur, et elle ouvre un chemin direct vers votre réseau privé.
Les alternatives courantes ont chacune leurs limites : Cloudflare Tunnel passe l'intégralité de vos flux par les serveurs Cloudflare, ce qui pose des questions de confidentialité et impose leur infrastructure. Tailscale/Headscale crée un réseau mesh entre vos machines, ce qui est excellent pour les accès point-à-point — mais n'est pas conçu pour exposer publiquement un service HTTP(S) avec un sous-domaine dédié. Pangolin occupe un espace différent : un relais WireGuard self-hosted, avec gestion des certificats et des sous-domaines, que vous contrôlez entièrement depuis votre VPS.
Ce que Pangolin apporte face aux alternatives
- Self-hosted complet — vos flux transitent par votre VPS uniquement, aucun tiers ne voit votre trafic applicatif.
- Pas d'ouverture de port entrant — la connexion est initiée depuis la machine d'origine vers le VPS (sens sortant), le NAT n'est jamais un obstacle.
- HTTPS automatique via Let's Encrypt — Pangolin gère les certificats pour chaque sous-domaine exposé, sans intervention manuelle.
- Interface web intégrée — ajout de tunnels, gestion des ressources et des utilisateurs depuis un panneau web, sans éditer de fichiers de configuration.
- Chiffrement de bout en bout WireGuard — le tunnel entre la machine d'origine et le VPS est chiffré au niveau transport, indépendamment du HTTPS applicatif.
- Multisite — un seul Pangolin sur le VPS peut relayer des dizaines de services depuis des machines différentes, sous des sous-domaines distincts.
Architecture : VPS relay, Gerbil et Newt
Pangolin repose sur trois composants qui se répartissent les rôles :
[Machine d'origine] [VPS ServOrbit] [Internet]
service:8080 Pangolin (orchestration)
newt (client) ←─WireGuard UDP─→ Gerbil (tunnel WG) ←─HTTPS──→ visiteur
Traefik (reverse proxy)Pangolin est le plan de contrôle : il gère les tunnels, les sous-domaines, les certificats et les utilisateurs via une API REST et une interface web. Il tourne sur le VPS.
Gerbil est le pair WireGuard côté serveur. Il ouvre un port UDP, établit les tunnels avec les clients, et route le trafic entrant vers les services exposés. Il tourne également sur le VPS, aux côtés de Pangolin.
Newt est le client léger qui tourne sur la machine d'origine (NAS, Pi, VM locale). Il contacte Gerbil sur le port UDP WireGuard, maintient le tunnel actif, et redirige le trafic reçu vers le service local sur le port configuré.
Le flux concret : un visiteur arrive sur nextcloud.mondomaine.com → Traefik (géré par Pangolin) reçoit la requête HTTPS → la transmet via Gerbil au tunnel WireGuard actif → Newt la reçoit et la relaie vers localhost:8080 sur la machine d'origine. Le service répond par le même chemin en sens inverse.
Prérequis
Côté VPS :
- VPS avec accès root et IPv4 dédiée — le plan {{vps.start.name}} suffit pour démarrer (1 vCPU, 1 Go de RAM pour des charges légères, 2 Go recommandés pour plusieurs tunnels actifs).
- Ubuntu 22.04 ou 24.04 (Debian 12 fonctionne également).
- Un port UDP libre pour WireGuard (par défaut 51820, configurable).
- Un nom de domaine avec accès à la gestion DNS — vous devrez créer un enregistrement wildcard *.mondomaine.com pointant vers l'IP du VPS.
- Docker et Docker Compose installés (apt install docker.io docker-compose-plugin).
Côté machine d'origine :
- Une machine Linux (Raspberry Pi, NAS sous DSM 7+, VM Proxmox, serveur physique) avec accès sortant UDP vers le port WireGuard du VPS — la plupart des FAI le laissent passer.
- Un service qui écoute sur un port local (Nextcloud, Gitea, Home Assistant, etc.).
Version actuelle : Pangolin 1.23.0 (sortie le 16 septembre 2026).
Déploiement de Pangolin et Gerbil sur le VPS
Préparer le VPS et ouvrir le port WireGuard
Connectez-vous en root sur le VPS et installez Docker s'il n'est pas déjà présent :
apt update && apt install -y docker.io docker-compose-plugin ufwOuvrez le port UDP pour WireGuard (51820 par défaut) et assurez-vous que les ports HTTP/HTTPS sont accessibles :
ufw allow 80/tcp ufw allow 443/tcp ufw allow 51820/udp ufw enableSi vous souhaitez restreindre l'accès au panneau d'administration (port 3000 par défaut), limitez-le à votre IP :
ufw allow from VOTRE_IP to any port 3000Créer le fichier docker-compose.yml
Créez un dossier de travail et le fichier de configuration :
mkdir -p /opt/pangolin && cd /opt/pangolinCréez
docker-compose.ymlavec le contenu suivant :cat > docker-compose.yml <<'EOF' services: pangolin: image: fosrl/pangolin:1.23.0 container_name: pangolin restart: unless-stopped volumes: - ./config:/app/config - ./data:/app/data ports: - "3000:3000" networks: - pangolin_net gerbil: image: fosrl/gerbil:latest container_name: gerbil restart: unless-stopped cap_add: - NET_ADMIN volumes: - ./data:/var/lib/gerbil ports: - "51820:51820/udp" networks: - pangolin_net depends_on: - pangolin networks: pangolin_net: driver: bridge EOFAdaptez le numéro de version de l'image
pangolinà la dernière release disponible sur GitHub.Configurer Pangolin et démarrer la stack
Créez le dossier de configuration et un fichier
config.ymlminimal :mkdir -p /opt/pangolin/config cat > /opt/pangolin/config/config.yml <<'EOF' app: base_domain: mondomaine.com admin_email: [email protected] port: 3000 wireguard: port: 51820 subnet: 10.0.0.0/24 acme: enabled: true staging: false EOFRemplacez
mondomaine.compar votre domaine réel. Démarrez la stack :cd /opt/pangolin && docker compose up -d docker compose logs -f pangolinPangolin génère un mot de passe administrateur au premier démarrage — notez-le depuis les logs. L'interface web est accessible sur
http://IP_VPS:3000.Configurer le DNS wildcard
Dans votre zone DNS, créez un enregistrement A wildcard pointant vers l'IP du VPS :
*.mondomaine.com → A → IP_VPSSur Cloudflare, créez ce même enregistrement avec le proxy désactivé (DNS-only, nuage gris) pour que les certificats Let's Encrypt puissent être émis correctement via le défi HTTP-01 utilisé par Pangolin.
Créer une unité systemd pour le redémarrage automatique
Docker avec
restart: unless-stoppedsuffit généralement, mais si vous préférez une unité systemd dédiée :cat > /etc/systemd/system/pangolin.service <<'EOF' [Unit] Description=Pangolin reverse tunnel stack After=docker.service Requires=docker.service [Service] Type=oneshot RemainAfterExit=yes WorkingDirectory=/opt/pangolin ExecStart=/usr/bin/docker compose up -d ExecStop=/usr/bin/docker compose down [Install] WantedBy=multi-user.target EOF systemctl daemon-reload systemctl enable pangolin
Ajout d'un tunnel avec Newt sur la machine d'origine
Créer un tunnel dans l'interface Pangolin
Connectez-vous à l'interface web Pangolin sur
http://IP_VPS:3000avec les identifiants admin. Allez dans Sites → Ajouter un site, donnez-lui un nom (ex.homelab) et notez le token de site généré. Puis dans Ressources → Ajouter une ressource, choisissez le site, saisissez le sous-domaine souhaité (nextcloud.mondomaine.com) et le port local de la machine d'origine (ex.8080).Installer Newt sur la machine d'origine
Sur la machine qui héberge votre service, téléchargez le binaire Newt correspondant à votre architecture :
# Sur Linux x86_64 curl -Lo /usr/local/bin/newt \ https://github.com/fosrl/newt/releases/latest/download/newt-linux-amd64 chmod +x /usr/local/bin/newtPour un Raspberry Pi (ARM64) :
curl -Lo /usr/local/bin/newt \ https://github.com/fosrl/newt/releases/latest/download/newt-linux-arm64 chmod +x /usr/local/bin/newtConfigurer et démarrer Newt
Lancez Newt avec le token de site récupéré à l'étape précédente :
newt \ --server https://mondomaine.com:3000 \ --token VOTRE_TOKEN_DE_SITE \ --target localhost:8080Pour un démarrage automatique, créez une unité systemd :
cat > /etc/systemd/system/newt.service <<'EOF' [Unit] Description=Newt WireGuard tunnel client After=network.target [Service] ExecStart=/usr/local/bin/newt \ --server https://mondomaine.com:3000 \ --token VOTRE_TOKEN_DE_SITE \ --target localhost:8080 Restart=always RestartSec=5 [Install] WantedBy=multi-user.target EOF systemctl daemon-reload systemctl enable --now newtVérifier la connectivité end-to-end
Sur le VPS, vérifiez que le tunnel WireGuard est établi :
docker exec gerbil wg showVous devriez voir un peer avec un
latest handshakerécent. Depuis n'importe quel navigateur ou en ligne de commande :curl -I https://nextcloud.mondomaine.comRéponse attendue :
HTTP/2 200(ou la page de connexion de votre service). Le certificat Let's Encrypt est émis automatiquement au premier accès.
Exposition d'un service : exemple Nextcloud derrière NAT
Configurer Nextcloud pour accepter le domaine proxy
Nextcloud bloque les requêtes venant de domaines non déclarés. Ajoutez le domaine public à
config.php:# Depuis la machine d'origine, dans le dossier Nextcloud nano config/config.phpAjoutez dans le tableau
trusted_domains:'trusted_domains' => array ( 0 => 'localhost', 1 => 'nextcloud.mondomaine.com', ), 'overwritehost' => 'nextcloud.mondomaine.com', 'overwriteprotocol' => 'https',Vérifier l'accès public et le certificat
Attendez 30 à 60 secondes après le premier accès pour que Let's Encrypt émette le certificat, puis :
curl -v https://nextcloud.mondomaine.com 2>&1 | grep -E 'subject|issuer|HTTP'Le certificat est signé par Let's Encrypt et l'URL publique est désormais accessible depuis n'importe quel réseau, sans aucun port ouvert côté réseau local.
Sécurité : tokens, rotation et contrôle d'accès
Rotation des tokens de site — générez un nouveau token depuis l'interface Pangolin et mettez à jour l'unité systemd de Newt sur la machine d'origine. L'ancien token est immédiatement invalidé. Planifiez cette rotation tous les 90 jours ou à chaque changement de personnel ayant accès à la machine d'origine.
Restrictions IP dans Pangolin — pour chaque ressource exposée, vous pouvez définir une liste blanche d'IP dans Ressources → Politique d'accès. Utile pour restreindre l'accès à votre backoffice ou à vos outils internes à votre plage d'IP de bureau.
Accès authentifié — Pangolin prend en charge les providers OIDC (Authentik, Keycloak, Zitadel) pour ajouter une couche d'authentification devant n'importe quelle ressource exposée, sans modifier l'application derrière le tunnel.
Restriction du port d'administration — le port 3000 de Pangolin ne doit pas être accessible publiquement. Restreignez-le à votre IP avec ufw allow from VOTRE_IP to any port 3000 && ufw deny 3000.
Dépannage
Le tunnel ne s'établit pas — UDP bloqué par le FAI. Certains opérateurs filtrent l'UDP sortant sur des ports non standard. Testez depuis la machine d'origine : nc -u -v IP_VPS 51820. Si la connexion est refusée, changez le port WireGuard dans config.yml pour 443 (UDP) ou 53 (UDP) — ces ports passent presque toujours. Mettez à jour ufw sur le VPS en conséquence.
MTU mismatch — latence ou coupures aléatoires. WireGuard ajoute un overhead d'encapsulation (environ 60 octets). Si votre service transfère de gros fichiers et que vous observez des coupures, réduisez le MTU de l'interface WireGuard dans la configuration Gerbil : mtu = 1380 est une valeur sûre sur la plupart des liaisons.
Service non joignable après tunnel actif. Vérifiez d'abord que le service local écoute bien sur 0.0.0.0 et non uniquement sur 127.0.0.1 : ss -tlnp | grep 8080. Ensuite, confirmez que le port configuré dans Pangolin correspond au port réel du service. Enfin, vérifiez les logs de Newt : journalctl -u newt -f.
Certificat Let's Encrypt non émis. Pangolin utilise le défi HTTP-01, qui exige que le port 80 du VPS soit joignable depuis Internet. Vérifiez que ufw allow 80/tcp est actif et qu'aucun autre service ne tient le port 80 (ss -tlnp | grep :80). Sur Cloudflare, assurez-vous que l'enregistrement wildcard est en DNS-only (nuage gris).
Interface Pangolin inaccessible après redémarrage. Si Docker redémarre avant que le réseau soit disponible, Pangolin peut démarrer sans interface réseau. Ajoutez network-online.target dans la dépendance systemd, ou relancez simplement docker compose up -d depuis /opt/pangolin.
Pangolin vs Cloudflare Tunnel vs Tailscale/Headscale
Faites défiler le tableau
| Critère | Pangolin + Gerbil | Cloudflare Tunnel | Tailscale / Headscale |
|---|---|---|---|
| Hébergement | Self-hosted sur votre VPS | SaaS Cloudflare | SaaS (Tailscale) ou self-hosted (Headscale) |
| Coût | Coût du VPS uniquement | Gratuit jusqu'à certains seuils, puis abonnement | Gratuit (usage perso), abonnement équipe |
| Chiffrement E2E | WireGuard entre la machine et le VPS, HTTPS jusqu'au visiteur | TLS jusqu'aux serveurs Cloudflare (déchiffré en transit) | WireGuard entre tous les nœuds (mesh complet) |
| Exposition HTTP publique | Oui, avec HTTPS automatique et sous-domaines personnalisés | Oui, avec certificats gérés par Cloudflare | Non prévu nativement (nécessite un reverse proxy en plus) |
| Complexité d'administration | Moyenne — une stack Docker à maintenir, une interface web | Faible — connector en un binaire, tout géré côté Cloudflare | Faible (Tailscale) à Moyenne (Headscale auto-hébergé) |
| Confidentialité du trafic | Trafic visible uniquement sur votre VPS | Trafic déchiffré par Cloudflare sur leurs serveurs | Trafic chiffré en mesh, jamais centralisé |
Aller plus loin
Pangolin 1.23.0 introduit le support de la haute disponibilité en édition Enterprise et la gestion de plusieurs administrateurs serveur — des fonctionnalités utiles dès que votre infrastructure dépasse un usage personnel.
Pour exposer des services non-HTTP (SSH privé, base de données, protocoles UDP applicatifs), Pangolin prend désormais en charge les ressources TCP/UDP privées accessibles via le client Newt — sans les exposer publiquement sur une URL, mais en les rendant accessibles depuis votre réseau WireGuard.
Si votre besoin est différent — coordonner l'accès entre plusieurs machines sans exposition publique — Headscale sur VPS est l'outil adapté. Pour une exposition sans VPS intermédiaire en utilisant l'infrastructure Cloudflare, Cloudflare Tunnel reste l'option la plus simple. Et pour poser les bases du chiffrement réseau sur VPS, le guide WireGuard sur VPS couvre l'installation et la configuration de l'interface WireGuard native.