Skip to content

Tsdproxy Docker : reverse proxy automatique Tailscale pour conteneurs

Brandon Visca
Date de publication:

💡 TL;DR

  • Tsdproxy expose automatiquement tes conteneurs Docker sur ton réseau Tailscale sans écrire un seul fichier de conf
  • Un label tsdproxy.enable=true suffit pour créer une entrée DNS dans ton tailnet
  • Plus besoin de configurer tailscale serve manuellement pour chaque service
  • Zéro port ouvert sur Internet, zéro domaine public, zéro Certbot

Table des matières

Table des matières

Pourquoi Tsdproxy Docker change tout pour Tailscale

Tailscale est déjà une merveille. Tu as un réseau mesh sécurisé entre tes appareils, tu n’ouvres aucun port sur ta box, et tout communique comme si tu étais sur le même LAN. Mais quand tu veux exposer un service Docker (un dashboard, un wiki, un serveur de musique) à ton tailnet sans le rendre public sur Internet, tu arrives à la case manuelle.

La méthode classique, c’est de taper tailscale serve --bg --set-path=/ monservice 8080 pour chaque conteneur. Si tu en as cinq, c’est cinq commandes. Si tu en rajoutes un sixième dans deux semaines, tu as oublié la syntaxe et tu retournes sur la doc. Si tu supprimes un conteneur, tu dois nettoyer les routes à la main. C’est pénible.

Tsdproxy docker résout ce problème en automatisant l’intégration entre Docker et Tailscale. Il écoute les événements Docker (création, suppression de conteneurs) et met à jour les routes Tailscale serve automatiquement. Tu ajoutes un label dans ton docker-compose.yml, tu lances le conteneur, et paf : ton service est accessible sur http://mon-service.ton-tailnet.ts.net depuis n’importe quel appareil connecté à Tailscale.

C’est particulièrement utile si tu as déjà adopté WireGuard pour ton VPN et que tu cherches une couche de publication de services encore plus simple pour ton homelab interne. Pas de certificats SSL à gérer, pas de DNS public à configurer, pas de reverse proxy à maintenir. Si tu débutes avec Docker, mon guide pour les débutants t’explique comment monter ta stack avant d’ajouter Tsdproxy.

Tsdproxy Docker, c’est quoi exactement ?

Tsdproxy est un reverse proxy automatique écrit en Go par almeidap (dépôt GitHub almeidap/tsdproxy). Son fonctionnement est simple : il tourne dans un conteneur tsdproxy docker avec accès au socket Docker et à la CLI Tailscale. Quand il détecte un conteneur avec le label tsdproxy.enable=true, il crée automatiquement une règle tailscale serve qui expose le port interne du conteneur sur le tailnet.

Ce qu’il fait bien :

Ce qu’il ne fait pas :

Prérequis

Avant de déployer Tsdproxy, assure-toi d’avoir :

Si tu utilises Tailscale en mode --accept-dns=true (par défaut), les noms de machine seront résolus automatiquement dans ton tailnet. Pas besoin de toucher à un DNS externe.

Le Docker Compose

Voici le fichier docker-compose.yml minimal pour déployer Tsdproxy. Il doit tourner sur le même hôte que les conteneurs que tu veux exposer, avec accès au socket Docker et au daemon Tailscale.

services:
  tsdproxy:
    image: ghcr.io/almeidap/tsdproxy:latest
    container_name: tsdproxy
    restart: unless-stopped
    environment:
      - TSD_API_KEY=tskey-api-XXXXXXXXXXXXXXXXXXXX
      - TSD_EPHEMERAL=false
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /var/lib/tailscale:/var/lib/tailscale
    networks:
      - proxy

networks:
  proxy:
    external: true

Points importants :

Crée le réseau avant de lancer :

docker network create proxy

Lance Tsdproxy :

docker compose up -d

Configurer les labels Docker

Voici la partie magique. Pour exposer un conteneur sur ton tailnet, tu n’as besoin que de deux labels dans son docker-compose.yml :

services:
  uptime-kuma:
    image: louislam/uptime-kuma:1
    container_name: uptime-kuma
    restart: unless-stopped
    volumes:
      - uptime-kuma-data:/app/data
    networks:
      - proxy
    labels:
      - "tsdproxy.enable=true"
      - "tsdproxy.port=3001"

Résultat : Uptime Kuma est accessible à http://uptime-kuma.ton-tailnet.ts.net depuis n’importe quel appareil connecté à Tailscale. Aucune commande manuelle, aucun fichier de config.

Tu peux aussi personnaliser le nom de la machine avec tsdproxy.name :

    labels:
      - "tsdproxy.enable=true"
      - "tsdproxy.port=8080"
      - "tsdproxy.name=mon-dashboard"

L’URL deviendra alors http://mon-dashboard.ton-tailnet.ts.net.

Un autre exemple avec Jellyfin :

  jellyfin:
    image: jellyfin/jellyfin:latest
    container_name: jellyfin
    restart: unless-stopped
    volumes:
      - jellyfin-config:/config
      - /mnt/media:/media:ro
    networks:
      - proxy
    labels:
      - "tsdproxy.enable=true"
      - "tsdproxy.port=8096"

Si tu utilises Caddy ou Traefik sur ton serveur, Tsdproxy ne les remplace pas. Il les complète en offrant un accès direct via Tailscale pour les services que tu ne veux pas exposer sur Internet.

Fonctionnement sous le capot

Tsdproxy repose sur trois briques simples :

  1. Docker Events : il écoute le socket Docker pour les événements start, stop et die.
  2. Tailscale API : pour chaque conteneur labellisé, il appelle l’API Tailscale pour créer un serveur web accessible sur le tailnet.
  3. Nommage DNS : le nom de la machine est automatiquement enregistré dans le DNS interne Tailscale.

Quand tu fais docker compose up -d avec un nouveau label tsdproxy.enable, Tsdproxy détecte l’événement en quelques secondes et crée la route. Quand tu fais docker compose down, la route disparaît automatiquement. Pas de routes fantômes, pas de nettoyage manuel.

Tailscale gère nativement le HTTPS pour les noms de machine. Quand tu accèdes à https://uptime-kuma.ton-tailnet.ts.net, Tailscale fournit un certificat Let’s Encrypt valide pour ton tailnet. Tu n’as pas besoin de gérer des certificats toi-même.

Comparatif : Tsdproxy vs Traefik + Tailscale vs Caddy

CritèreTsdproxyTraefik + TailscaleCaddy + Tailscale
ConfigurationZéro (labels Docker)Labels + fichiers YAML/TOMLCaddyfile
Découverte autoOui (Docker events)Oui (providers Docker)Non (Caddyfile statique)
HTTPSGéré par Tailscale natifLet’s Encrypt + TailscaleLet’s Encrypt natif
Exposition InternetNon (tailnet uniquement)Possible (optionnel)Possible (optionnel)
Domaine requisNon (Tailscale DNS)Oui (si public)Oui (si public)
Idéal pourHomelab tailnet purArchitecture hybride publique/privéeSimplicité HTTPS publique

Mon avis : si tous tes services sont destinés à rester dans ton tailnet sans jamais toucher Internet public, Tsdproxy est la solution la plus simple. Si tu veux certains services publics et d’autres privés, garde Traefik pour le public et ajoute Tsdproxy pour le privé.

Sécurité et bonnes pratiques

Même si tout reste dans ton tailnet, quelques règles à respecter :

Dépannage rapide

Le conteneur n’apparaît pas sur le tailnet

Vérifie que Tsdproxy est bien lancé et qu’il a accès au socket Docker : docker logs tsdproxy. Tu dois voir des lignes du type Detected container: uptime-kuma.

Erreur “invalid API key”

La clé API Tailscale a expiré ou n’a pas les bons droits. Régénère une clé depuis la console avec les permissions “Device” et “Tailnet settings”.

Le nom DNS ne résout pas

Vérifie que le client Tailscale sur ton appareil client a bien Accept DNS activé. Sur mobile, c’est dans les paramètres de l’app. Sur Linux, vérifie --accept-dns=true.

Conflit de noms de machine

Si deux conteneurs ont le même nom, Tailscale refuse d’enregistrer le second. Utilise tsdproxy.name pour forcer un nom unique.

Conclusion

Tsdproxy est ce qu’il manquait à l’écosystème Tailscale + Docker. Il transforme l’exposition de services internes d’une corvée manuelle en une découverte automatique fluide. Tu ajoutes deux labels dans un docker-compose.yml, tu lances ton conteneur, et il est immédiatement accessible depuis ton téléphone, ton laptop ou ta tablette via le tunnel sécurisé Tailscale.

Pour un homelab où la simplicité prime, c’est probablement le meilleur combo actuel. Pas de reverse proxy à configurer, pas de port à ouvrir sur ta box, pas de Certbot à maintenir. Juste du Docker, du Tailscale, et Tsdproxy qui fait le lien.

Si tu veux d’autres outils pour sécuriser ton homelab, jette un œil à mon guide WireGuard Docker pour un VPN de couche inférieure, ou à mes guides pour Caddy et Traefik si tu as besoin d’une exposition publique. Bon auto-hébergement !

Previous
Dashy Docker : ton dashboard homelab ultra-personnalisable avec widgets
Next
Changedetection Docker : guide complet pour surveiller n'importe quel site web (alternative Distill.io)