Aller au contenu
Sécurité medium

Pangolin : exposer un service sans ouvrir de port

16 min de lecture

logo pangolin

Pangolin publie un service interne sur Internet via un tunnel WireGuard sortant, sans ouvrir le moindre port entrant, et vous en gardez tout le plan de contrôle. C'est l'équivalent auto-hébergé et souverain du tunnel Cloudflare : même confort (rien à exposer, certificats automatiques, couche d'identité devant chaque service), mais l'infrastructure de coordination vous appartient. Ce guide monte Pangolin de bout en bout, expose un service à travers le tunnel, le protège par authentification, puis traite le revers de la médaille : c'est un outil à double tranchant dont il faut savoir détecter l'abus. Public : sysadmins et équipes plateforme (niveau avancé).

  • Comprendre l'architecture Pangolin : hub reverse proxy + tunnel Newt sortant.
  • Installer le hub sur un serveur public, avec certificats Let's Encrypt automatiques.
  • Connecter un réseau privé via le connecteur Newt, sans ouvrir de port.
  • Exposer un service et le protéger (SSO, code PIN, liste blanche).
  • Détecter l'abus de ce tunnel, en lien avec le modèle de menaces (ATT&CK T1090, T1572).
  • Un serveur Linux public (VPS ou VM cloud) avec une IP publique et les ports 80/443 TCP et 51820/21820 UDP ouverts. Une VM à 2 vCPU / 4 Go suffit largement.
  • Un nom de domaine que vous contrôlez, avec un enregistrement pour le tableau de bord et un wildcard pour les services exposés.
  • Docker Engine et le plugin Compose installés (voir plus bas, méthode par dépôt signé).
  • Un réseau privé à exposer : ici un homelab derrière une box, mais ce peut être un cluster, un LAN d'entreprise ou un poste de dev.

Comment Pangolin expose un service sans ouvrir de port

Section intitulée « Comment Pangolin expose un service sans ouvrir de port »

Un reverse proxy classique attend les connexions entrantes : vous ouvrez le port 443 de votre pare-feu et le trafic public arrive jusqu'à vous. Pangolin inverse le sens. Un connecteur léger, Newt, installé sur votre réseau privé, ouvre une connexion sortante vers le hub Pangolin public. Le trafic des visiteurs entre par le hub, puis redescend vers votre service à travers ce tunnel WireGuard. Résultat : aucun port entrant sur votre réseau privé, donc rien à scanner ni à brute-forcer sur votre IP.

Le hub se compose de trois conteneurs complémentaires :

  • pangolin : l'application, le tableau de bord et l'API de gestion.
  • gerbil : la passerelle WireGuard qui termine les tunnels des sites.
  • traefik : le reverse proxy qui route le trafic HTTP et gère les certificats Let's Encrypt automatiquement.

Côté réseau privé, un seul composant : Newt, qui monte le tunnel et route le trafic vers vos services locaux. La même logique « zéro port entrant » que NetBird ou Tailscale, mais orientée publication de services web plutôt que mesh d'administration.

Avant l'installation, faites pointer votre domaine vers l'IP publique du serveur. Deux enregistrements suffisent : un pour le tableau de bord, un wildcard pour que chaque service exposé reçoive son propre sous-domaine avec un certificat dédié.

TypeNomValeur
Apangolin.votredomaine.frIP.publique.du.serveur
A*.pangolin.votredomaine.frIP.publique.du.serveur

Le wildcard est la clé : il permet à Pangolin d'émettre un certificat pour app.pangolin.votredomaine.fr, git.pangolin.votredomaine.fr et ainsi de suite, sans retoucher le DNS à chaque nouveau service.

Pangolin tourne en conteneurs. Installez Docker Engine depuis le dépôt officiel signé plutôt que par un script curl | sh, afin de bénéficier de la vérification GPG et des mises à jour.

Fenêtre de terminal
# Clé GPG officielle Docker + dépôt apt signé (Ubuntu/Debian)
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
-o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \
https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo $VERSION_CODENAME) stable" \
| sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

Vérifiez que tout répond avant de continuer :

Fenêtre de terminal
docker --version && docker compose version
# Doit afficher les versions de Docker Engine et du plugin Compose

Pangolin fournit un installateur qui génère la configuration et lance la stack. Téléchargez le binaire depuis les releases GitHub et contrôlez son empreinte avant de l'exécuter, plutôt que d'utiliser le curl | bash proposé par la documentation officielle.

Fenêtre de terminal
# Binaire installateur (Linux amd64), version épinglée
curl -fsSL -o installer \
https://github.com/fosrl/pangolin/releases/download/1.19.4/installer_linux_amd64
sha256sum installer # comparez à l'empreinte publiée sur la release
chmod +x installer
sudo ./installer

L'installateur pose une série de questions. Les réponses qui comptent pour un déploiement standard :

  • Base domain : pangolin.votredomaine.fr (le domaine racine des services).
  • Dashboard domain : pangolin.votredomaine.fr (le tableau de bord).
  • Let's Encrypt email : une adresse valide, pour les certificats.
  • Gerbil (tunneled connections) : oui, c'est ce qui active les tunnels.
  • Enterprise, PostgreSQL, SMTP, MaxMind : non pour un lab (SQLite et réglages par défaut suffisent).

Il génère alors un docker-compose.yml et un dossier config/, puis démarre les conteneurs. La stack déployée ressemble à ceci :

# docker-compose.yml (extrait) : les trois services du hub
services:
pangolin:
image: docker.io/fosrl/pangolin:1.19.4
gerbil:
image: docker.io/fosrl/gerbil:1.4.2
cap_add: [NET_ADMIN, SYS_MODULE]
ports:
- 51820:51820/udp # tunnel WireGuard des sites
- 21820:21820/udp # clients
- 443:443 # HTTPS public
- 80:80 # HTTP (challenge ACME + redirection)
traefik:
image: docker.io/traefik:v3.6
network_mode: service:gerbil # Traefik partage le réseau de gerbil

Vérifiez le démarrage et l'émission du certificat :

Fenêtre de terminal
cd /opt/pangolin && docker compose ps # les 3 conteneurs "Up", pangolin "healthy"
curl -sS -o /dev/null -w "%{http_code}\n" https://pangolin.votredomaine.fr/
# 200 : le tableau de bord répond avec un certificat Let's Encrypt valide

Au premier démarrage, Pangolin génère un jeton de configuration visible dans les logs. Il protège la page de création du premier administrateur.

Fenêtre de terminal
docker compose logs pangolin | grep -A2 "SETUP TOKEN"
# Copiez la valeur "Token: ..."

Ouvrez https://pangolin.votredomaine.fr/auth/initial-setup, collez le jeton, puis définissez l'email et le mot de passe de l'administrateur serveur. Vous accédez ensuite au tableau de bord et pouvez créer votre première organisation, qui regroupera vos sites et vos services.

Un site (appelé nœud dans l'interface) est un point d'entrée dans un réseau privé. Depuis la vue Nœuds, le bouton Ajouter un nœud lance l'assistant. Choisissez le type Site Newt, nommez-le, et Pangolin affiche les identifiants du tunnel ainsi que la commande d'installation du connecteur.

Assistant de création d'un nœud Newt dans Pangolin, avec l'endpoint, l'identifiant, le secret et la commande d'enrôlement

L'assistant propose un curl | bash pour installer Newt. Préférez le conteneur officiel épinglé, qui évite le script distant et se met à jour de façon contrôlée. Lancez-le sur une machine de votre réseau privé (le homelab), avec les identifiants affichés :

Fenêtre de terminal
docker run -d --name newt --restart unless-stopped \
--network host --cap-add NET_ADMIN --device /dev/net/tun \
fosrl/newt:1.14.0 \
--id VOTRE_ID_NEWT \
--secret VOTRE_SECRET_NEWT \
--endpoint https://pangolin.votredomaine.fr

Newt ouvre alors une connexion sortante vers le hub et monte le tunnel. Les logs le confirment :

Fenêtre de terminal
docker logs newt
# INFO Websocket connected
# INFO Tunnel connection to server established successfully!

De retour dans la vue Nœuds, le site apparaît En ligne, avec son débit et son type de connecteur. C'est la preuve que le tunnel est monté, alors qu'aucun port n'a été ouvert sur le réseau privé.

Vue des nœuds Pangolin : le site homelab est en ligne, connecté via Newt

Une ressource publie un service local sur un sous-domaine public. Créez-la depuis le menu Ressource, avec un sous-domaine (par exemple app) et le domaine wildcard. Pangolin assemble alors l'URL app.pangolin.votredomaine.fr et émet automatiquement son certificat. Il reste à indiquer le backend : le site Newt et l'adresse interne du service (par exemple 127.0.0.1:8099 pour un serveur web local).

Ressource App Homelab exposée en HTTPS via Pangolin

Le trafic suit désormais ce chemin : le navigateur du visiteur atteint le hub public, Traefik route vers la ressource, le trafic descend par le tunnel Newt jusqu'au service interne, et la réponse remonte. Le service tourne sur une machine sans IP publique et sans port ouvert, mais reste joignable depuis Internet.

Par défaut, une ressource HTTP est protégée par le SSO de Pangolin : un visiteur sans session est renvoyé vers un écran d'authentification avant d'atteindre le service. C'est la différence majeure avec une simple ouverture de port : l'identité est vérifiée au bord, avant même que la requête n'atteigne votre réseau.

Écran d'authentification Pangolin protégeant la ressource App Homelab

L'onglet Authentification de la ressource contrôle finement qui passe. Vous combinez le SSO de la plateforme (avec restriction par rôles ou utilisateurs) et des méthodes complémentaires : code PIN, code confidentiel partagé, liste blanche d'e-mails avec mots de passe à usage unique, ou authentification par en-tête pour du machine-to-machine.

Onglet Authentification d'une ressource Pangolin : SSO, code PIN, code confidentiel, liste blanche

Le fait d'auto-héberger le plan de contrôle est un avantage défensif net face au tunnel Cloudflare : un attaquant ne peut pas détourner votre hub. Mais deux angles d'abus subsistent, et il faut les traiter.

Premier angle : Newt est un tunnel sortant générique. Comme cloudflared, c'est un seul binaire qu'un attaquant déjà présent peut déposer sur une machine et pointer vers son propre hub Pangolin, pour du command and control ou de l'exfiltration. Le trafic est chiffré et sortant, donc il traverse le pare-feu sans règle entrante et se fond dans le trafic légitime. Dans le langage MITRE ATT&CK, c'est du T1090 (proxy) et du T1572 (tunneling), au service du command and control.

Second angle : une ressource mal configurée. Une ressource dont le SSO est désactivé publie un service interne sur Internet sans authentification. Un attaquant qui obtient un accès au tableau de bord peut aussi exposer délibérément une base de données ou une application d'administration.

La détection est comportementale, puisque le contenu est chiffré :

  • Exécution d'un processus ou conteneur newt que vous n'avez pas déployé, surtout avec un --endpoint pointant vers un domaine inconnu.
  • Connexions sortantes vers un hub : TCP 443 (canal de contrôle websocket) doublé d'UDP 51820 (données WireGuard) vers une même IP.
  • Fichier de configuration ~/.config/newt-client/config.json créé sur un hôte qui ne devrait pas tunneliser.
Fenêtre de terminal
# Repérer un newt non autorisé et son tunnel sortant
pgrep -a newt ; docker ps --filter ancestor=fosrl/newt
sudo ss -tunp | grep -E '51820|newt'

Les parades qui tiennent : filtrage egress (une machine interne ne devrait pas parler WireGuard à un hub inconnu), whitelisting applicatif avec fapolicyd pour empêcher l'exécution d'un newt déposé par un attaquant, inventaire des sites et ressources déclarés, et revue régulière des ressources dont l'authentification est désactivée.

  1. Pangolin expose un service sans ouvrir de port : un tunnel WireGuard sortant (Newt) remplace l'ouverture du pare-feu.
  2. Vous gardez le plan de contrôle : c'est l'alternative souveraine au tunnel Cloudflare, hub et données chez vous.
  3. Le hub tient en trois conteneurs (pangolin, gerbil, traefik) avec certificats Let's Encrypt automatiques via un wildcard DNS.
  4. L'identité est vérifiée au bord : SSO, code PIN, liste blanche ; une ressource sans authentification fuit sur Internet.
  5. C'est un outil à double tranchant : Newt est un tunnel sortant générique (T1090/T1572), et une ressource mal réglée expose un service interne.
  6. La défense, c'est la détection : newt inattendu, egress 443 + UDP 51820, filtrage egress et whitelisting applicatif.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn