Cloudflare Tunnel avec Docker sur Unraid : publier des services sans ouvrir de port

Déployez cloudflared dans Docker sur Unraid, publiez un service par HTTPS sans redirection de port et protégez-le avec Cloudflare Access.

01

Un tunnel sortant remplace la redirection de port

Cloudflare Tunnel inverse le modèle habituel. Au lieu d’ouvrir un port sur le routeur et d’attendre les connexions Internet, le conteneur cloudflared établit lui-même des connexions sortantes vers le réseau Cloudflare. Un nom comme photos.exemple.ca est ensuite associé à un service local, par exemple http://immich:2283.

L’adresse publique du domicile et le port de l’application ne sont donc pas annoncés dans le DNS. Le routeur n’a aucune redirection à créer, et le tunnel fonctionne aussi derrière une adresse IP dynamique ou un CGNAT. Cloudflare termine la connexion publique HTTPS, applique ses contrôles, puis transporte la requête dans le tunnel jusqu’à cloudflared.

Cela réduit la surface exposée, mais ne rend pas automatiquement l’application sûre. Sans Cloudflare Access, un nom d’hôte publié demeure accessible à tous sur Internet. Il faut encore mettre à jour l’application, protéger ses comptes, limiter les routes et décider si elle devrait être publique, protégée par identité ou accessible seulement par un réseau privé.

Chemin d’une requête
Navigateur
   │ HTTPS
   ▼
Cloudflare Edge ── politiques WAF / Access
   │ tunnel chiffré établi de l’intérieur
   ▼
cloudflared sur Unraid ── réseau Docker privé ── application:port

Routeur : aucune redirection de port vers Unraid
02

Choisir ce qui doit vraiment être publié

Commencez avec une seule application Web peu critique. Un tableau de bord, une application photo ou un outil interne avec une authentification correcte convient mieux à un premier essai que l’interface d’administration Unraid. Ne publiez jamais directement le socket Docker, SMB, NFS, l’hyperviseur, IPMI, SSH ou la console d’un pare-feu sous un simple nom d’hôte Web.

Cloudflare Tunnel sait aussi transporter certains protocoles non HTTP, mais leur accès demande un client et une stratégie adaptés. Pour administrer tout un réseau, un VPN ou Cloudflare One Client avec des routes privées est généralement plus cohérent qu’une collection de services TCP publiés.

Attention aux applications mobiles, aux agents et aux webhooks. Une page Web sait suivre la redirection de connexion Cloudflare Access; un client natif ou une intégration automatisée ne le sait pas toujours. Séparez les usages par nom d’hôte et prévoyez un jeton de service, une authentification mTLS ou une route privée lorsque le navigateur n’est pas présent.

ServiceApproche recommandéeÀ éviter
Application Web personnelleTunnel + Access + authentification de l’applicationPublication anonyme par défaut
Webhook ou APINom distinct + jeton de service ou mTLSContourner Access pour tout le site
Administration UnraidVPN ou accès privé avec appareil géréExposer la WebGUI sur Internet
SSH, SMB ou RDPAccès privé ou client cloudflared appropriéLes traiter comme un site Web public
Vidéo et gros fichiersValider le produit et les modalités CloudflareUtiliser le CDN gratuit comme plateforme média
03

Préparer le domaine, le réseau et un plan de retour

Le domaine utilisé doit être actif dans Cloudflare. Le serveur Unraid doit résoudre le DNS, garder une heure exacte et joindre Cloudflare. cloudflared utilise le port sortant 7844 : UDP pour QUIC ou TCP pour HTTP/2. Le mode automatique essaie QUIC puis retombe sur HTTP/2 si l’UDP ne passe pas. Autorisez les deux protocoles pour éviter une dépendance inutile.

Inventoriez l’adresse locale de l’application, son protocole et son port avant de créer le tunnel. Testez cette adresse depuis le même réseau que cloudflared. Si le service écoute seulement sur 127.0.0.1, sur un autre réseau Docker ou sur HTTPS avec un certificat invalide, le tunnel pourra être Healthy tout en retournant une erreur 502.

Retirez les anciennes redirections de port seulement après avoir validé le nouveau chemin depuis un réseau cellulaire. Conservez une méthode d’administration privée indépendante, par exemple WireGuard ou Tailscale, pour pouvoir corriger le tunnel si Cloudflare, DNS ou le conteneur ne répond plus.

PrérequisValeur à noterTest
Zone DNS Cloudflareexemple.caLa zone est active et les serveurs DNS sont corrects
Nom publicapp.exemple.caAucun ancien A, AAAA ou CNAME conflictuel
Originehttp://application:8080Répond depuis le réseau de cloudflared
Sortie réseauUDP et TCP 7844Aucun filtrage ou inspection ne bloque les connexions
Accès de secoursVPN privéFonctionne avant de toucher aux ports du routeur
Retour arrièreAncienne URL et configuration documentéesPeut être rétabli sans improvisation
04

Créer un tunnel géré dans le tableau de bord

Cloudflare recommande un tunnel géré à distance pour la plupart des déploiements. Sa configuration et ses routes restent dans le tableau de bord, tandis que le conteneur Unraid n’a besoin que d’un jeton pour se connecter. Cette approche est plus simple à maintenir qu’un certificat de compte et plusieurs fichiers YAML locaux.

Dans Cloudflare, ouvrez Networking, Tunnels, choisissez Create a tunnel et donnez-lui un nom explicite comme unraid-maison. Sélectionnez Docker comme environnement. La commande affichée contient un long jeton commençant généralement par eyJ. Ne copiez pas ce jeton dans une capture d’écran, un message, un dépôt Git ou un modèle Unraid partagé.

Toute personne qui possède ce jeton peut lancer un connecteur pour le tunnel. Il ne s’agit pas d’une simple clé de lecture. Nous le monterons dans le conteneur à partir d’un fichier protégé; si le jeton est exposé, utilisez Refresh token dans Cloudflare puis remplacez-le sur tous les connecteurs.

  • Cloudflare Dashboard > Networking > Tunnels > Create a tunnel.
  • Nommer le tunnel selon son emplacement et son rôle.
  • Choisir Docker et extraire seulement le jeton de la commande proposée.
  • Ne pas encore créer de route publique si la politique Access n’est pas prête.
  • Conserver l’identifiant du propriétaire du tunnel et la procédure de rotation.
05

Préparer Unraid sans inscrire le jeton dans l’historique

Un tunnel géré à distance n’a pas besoin de volume de configuration complet. Créez seulement un répertoire persistant dans appdata et un fichier contenant le jeton. La commande suivante lit le secret sans l’afficher à l’écran et évite de l’inscrire directement dans l’historique du terminal.

Le paramètre token-file est pris en charge par cloudflared 2025.4.0 ou une version plus récente. Montez le fichier en lecture seule dans le conteneur. Une variable d’environnement TUNNEL_TOKEN fonctionne aussi, mais sa valeur demeure visible aux administrateurs capables d’inspecter le conteneur; le fichier rend au moins la gestion et la rotation plus propres.

Dans l’interface Unraid, les modèles de conteneur permettent de définir le réseau, les volumes, les variables et la commande. Si vous utilisez un modèle de Community Apps, confirmez que le dépôt est bien cloudflare/cloudflared et examinez les champs avant de saisir le secret; le modèle est distinct de l’image officielle.

Créer le fichier de jeton sur Unraid
mkdir -p /mnt/user/appdata/cloudflared
chmod 700 /mnt/user/appdata/cloudflared

read -rsp "Jeton du tunnel Cloudflare : " CF_TUNNEL_TOKEN
printf '%s' "$CF_TUNNEL_TOKEN" > /mnt/user/appdata/cloudflared/token
unset CF_TUNNEL_TOKEN
printf '\n'

chmod 600 /mnt/user/appdata/cloudflared/token
Créer un réseau Docker dédié s’il n’existe pas
docker network inspect tunnel >/dev/null 2>&1 || docker network create tunnel
06

Lancer cloudflared dans Docker

Le conteneur n’écoute sur aucun port publié. Il doit seulement joindre Cloudflare et l’origine locale. La commande ci-dessous utilise l’image officielle, monte le jeton en lecture seule, rejoint le réseau tunnel et redémarre après un redémarrage d’Unraid.

Dans un modèle Unraid, reproduisez les mêmes valeurs : Repository cloudflare/cloudflared:latest, Network Type Custom: tunnel, chemin hôte du jeton vers /run/secrets/tunnel-token en lecture seule, Auto Start activé et Post Arguments tunnel --no-autoupdate run --token-file /run/secrets/tunnel-token. N’ajoutez aucune redirection de port.

L’option no-autoupdate est normale dans un conteneur : l’image elle-même doit être remplacée pour mettre cloudflared à jour. Utilisez la notification de mise à jour Unraid, tirez la nouvelle image dans une fenêtre d’entretien et recréez le conteneur. Ne confondez pas l’état Healthy du tunnel dans Cloudflare avec la santé de l’application derrière lui.

Déploiement Docker équivalent
docker run -d \
  --name cloudflared \
  --restart unless-stopped \
  --network tunnel \
  --cap-drop ALL \
  --security-opt no-new-privileges:true \
  -v /mnt/user/appdata/cloudflared/token:/run/secrets/tunnel-token:ro \
  cloudflare/cloudflared:latest \
  tunnel --no-autoupdate run --token-file /run/secrets/tunnel-token
Première validation
docker logs --tail 100 cloudflared
docker inspect cloudflared --format '{{json .NetworkSettings.Networks}}'
docker exec cloudflared cloudflared --version
07

Relier cloudflared à l’application sans passer par Internet

Le chemin le plus propre place cloudflared et l’application sur le même réseau Docker défini par l’utilisateur. Docker fournit alors la résolution du nom du conteneur : l’origine peut être http://immich:2283 plutôt qu’une adresse IP qui changera au prochain redémarrage. L’application ne doit pas publier son port sur l’hôte uniquement pour que cloudflared la joigne.

Si l’application ne peut pas rejoindre ce réseau, utilisez son adresse privée sur le LAN et limitez le pare-feu à la source cloudflared et au port exact. Sur certaines versions d’Unraid, l’accès entre un réseau personnalisé et l’hôte demande un réglage particulier; consultez la documentation de la version plutôt que d’activer Host access to custom networks sans comprendre l’effet.

Dans le tunnel, ajoutez une route Published application. Choisissez le nom public et saisissez l’URL de service exacte. Une route créée dans le tableau de bord ajoute le DNS vers le sous-domaine cfargotunnel.com du tunnel. Si un enregistrement du même nom existe déjà, retirez le conflit avant de sauvegarder.

ApplicationService URL d’exempleRemarque
Application sur le même réseau Dockerhttp://application:8080Préféré; pas de port publié sur l’hôte
Service sur l’hôte Unraidhttps://192.168.1.10:8443Valider le certificat et limiter le flux local
Service sur une autre machinehttps://service.lan:443DNS interne et TLS fiables nécessaires
Route de rejet finalehttp_status:404Utile surtout avec une configuration locale multi-routes
Ajouter une application existante au réseau tunnel
docker network connect tunnel application

# Confirmer les réseaux du conteneur
docker inspect application --format '{{json .NetworkSettings.Networks}}'
08

Protéger le nom d’hôte avec Cloudflare Access

Pour un outil privé, créez idéalement l’application Access avant la route publique. Dans Zero Trust, Access controls, Applications, choisissez Self-hosted and private, ajoutez le même nom d’hôte et créez une politique Allow. Access refuse par défaut les utilisateurs qui ne correspondent à aucune politique d’autorisation.

Utilisez un fournisseur d’identité avec MFA lorsque possible : Cloudflare, Microsoft Entra ID, Google ou un autre IdP pris en charge. Le code à usage unique par courriel peut dépanner un petit environnement, mais la règle doit viser des adresses ou domaines précis. Autoriser simplement la méthode One-time PIN comme critère Include permettrait à n’importe quelle adresse de demander un code.

Le forfait Zero Trust gratuit accepte jusqu’à 50 utilisateurs. Il comprend le soutien communautaire et une rétention standard des journaux allant jusqu’à 24 heures; les fonctions, le soutien et la conservation plus longue varient avec les forfaits payants. Ce plafond ne signifie pas que toutes les fonctions Cloudflare ou tous les usages de bande passante sont gratuits.

Élément de politiqueExemple prudentPiège
ActionAllowCréer un Bypass global
IncludeCourriels précis ou groupe IdPInclure toute méthode OTP
RequireMFA, pays attendu ou appareil géré selon le risqueAccumuler des conditions impossibles à soutenir
SessionQuelques heures pour une console sensibleSession de plusieurs semaines
DenyPays ou identité explicitement interditsCroire que Deny remplace une règle Allow précise
09

Prévoir les clients qui ne savent pas afficher une page de connexion

Une application Web dans un navigateur fonctionne généralement bien avec Access. Un client mobile, un synchroniseur, une API ou un webhook peut toutefois recevoir la page de connexion HTML au lieu de la réponse attendue. Testez les parcours réels avant de considérer le déploiement terminé.

Pour un échange machine à machine, Cloudflare Access offre des jetons de service. Le client présente un identifiant et un secret dans les en-têtes attendus, tandis qu’une politique Service Auth ou une règle appropriée autorise la requête. Stockez ce secret comme un mot de passe, attribuez un jeton par intégration et planifiez sa rotation.

Ne désactivez pas Access pour tout le nom d’hôte afin de réparer un seul webhook. Utilisez plutôt api.exemple.ca ou un chemin protégé par une application Access distincte. Certaines applications doivent aussi connaître leur URL externe et faire confiance aux en-têtes de mandataire; suivez leur documentation pour éviter les boucles de redirection, les cookies non sécurisés ou les mauvaises URL de rappel.

  • Tester le navigateur, l’application mobile, les notifications, les téléchargements et les WebSockets.
  • Séparer l’interface humaine et l’API automatisée.
  • Créer un jeton de service par consommateur, avec une expiration.
  • Conserver l’authentification propre à l’application même derrière Access.
  • Valider les URL externes, les en-têtes de proxy et les cookies Secure.
10

Garder le chiffrement et le pare-feu cohérents

Le tunnel entre cloudflared et Cloudflare est chiffré. Le dernier segment, entre cloudflared et l’application, dépend de l’URL de service. HTTP peut être acceptable sur un réseau Docker privé limité au même hôte; si le trafic traverse un VLAN ou un réseau partagé, utilisez HTTPS et validez le certificat de l’origine.

Pour une origine HTTPS, configurez le nom attendu par le certificat avec Origin Server Name au besoin. Évitez No TLS Verify : cette option fait disparaître l’erreur en supprimant la vérification d’identité de l’origine. Un certificat interne approuvé ou le nom correct règle la cause sans affaiblir le lien.

Au pare-feu, autorisez cloudflared vers les destinations Cloudflare requises en TCP et UDP 7844, plus les services DNS et d’heure approuvés. L’accès à api.cloudflare.com en TCP 443 sert notamment aux fonctions de gestion et de mise à jour. Bloquez les connexions entrantes vers l’origine et limitez cloudflared aux ports locaux réellement publiés.

FluxActionCommentaire
cloudflared → CloudflareAutoriser TCP/UDP 7844HTTP/2 et QUIC; suivre les destinations officielles
cloudflared → api.cloudflare.comAutoriser TCP 443Gestion et contrôles de mise à jour
cloudflared → origineAutoriser le port exactAucun accès général au VLAN serveur
Internet → routeur/UnraidRefuserAucune redirection de port
Réseau utilisateur → origine localeSelon le besoinLe tunnel ne remplace pas la segmentation interne
11

Diagnostiquer avec une séquence courte

Un tunnel Healthy prouve que cloudflared rejoint Cloudflare; il ne prouve pas que l’origine répond. Commencez par l’état du conteneur et ses journaux, puis vérifiez le réseau Docker, l’URL de service, le protocole et le port. Testez finalement le nom public en navigation privée et sur un réseau cellulaire.

Une erreur 1033 indique généralement que Cloudflare ne trouve pas de connecteur sain pour le tunnel. Une 502 signifie souvent que cloudflared est connecté, mais ne peut pas joindre l’origine. Une erreur x509 pointe vers le certificat ou le nom TLS. Un échec QUIC sur UDP 7844 peut retomber sur HTTP/2 si TCP 7844 fonctionne; si les deux sont bloqués, le tunnel ne démarrera pas.

SymptômeCause probablePremier geste
Tunnel Inactive ou erreur 1033Conteneur arrêté, jeton invalide ou sortie bloquéeLire les journaux et tester 7844
502 Bad GatewayMauvais nom, port, protocole ou réseau DockerTester l’URL d’origine depuis le même réseau
x509 unknown authorityCertificat interne non approuvéInstaller l’autorité ou corriger Origin Server Name
Too many redirectsHTTPS ou en-têtes de proxy mal interprétésComparer l’URL externe et la configuration de l’application
Accès refusé par AccessIdentité hors politique ou session expiréeConsulter les journaux Access et tester la règle
Navigateur fonctionne, application mobile échoueLe client ne suit pas l’authentification AccessCréer un chemin API et une identité de service
Commandes de diagnostic Unraid
docker ps --filter name=cloudflared
docker logs --since 15m cloudflared
docker inspect cloudflared --format '{{json .NetworkSettings.Networks}}'
docker inspect application --format '{{json .NetworkSettings.Networks}}'

# Version et redémarrage contrôlé
docker exec cloudflared cloudflared --version
docker restart cloudflared
12

Mettre à jour, superviser et pouvoir révoquer

Activez le démarrage automatique du conteneur et les notifications de mise à jour Unraid. Après une mise à jour de l’image, confirmez la version, l’état du tunnel, une connexion Access et le fonctionnement de l’application. Les journaux de niveau debug peuvent contenir des URL et des en-têtes sensibles; ne les laissez pas activés en permanence.

Surveillez au minimum l’état du tunnel dans Cloudflare, les redémarrages du conteneur, les erreurs 5xx et les refus Access. L’endpoint Prometheus de cloudflared peut enrichir la supervision, mais ne le publiez pas sur Internet et limitez son accès au réseau de surveillance.

Sauvegardez le modèle du conteneur et la documentation des routes, politiques, propriétaires et applications. Ne multipliez pas les copies du jeton : une restauration sur un système non fiable donnerait la capacité de relancer le tunnel. Après un incident ou une restauration douteuse, rafraîchissez le jeton et supprimez les connexions non autorisées.

  • Mensuel : mises à jour de cloudflared et des applications publiées.
  • Trimestriel : politiques Access, utilisateurs actifs, jetons de service et routes DNS.
  • Après un changement : test externe, test de l’origine et examen des journaux.
  • Après une fuite : rotation du jeton Tunnel et révocation des secrets Access.
  • Au retrait d’un service : supprimer route, DNS, politique et accès local.
13

Checklist de mise en production

Le déploiement est prêt lorsque l’application fonctionne depuis Internet sans port entrant, qu’un utilisateur non autorisé est refusé et qu’une panne du tunnel n’empêche pas l’administration locale. Testez autant le refus que l’autorisation : un écran de connexion visible n’est pas une preuve que la politique bloque les mauvaises identités.

Le modèle reste volontairement simple : un tunnel géré à distance, un jeton en fichier, un réseau Docker limité, une route par application et Access devant les outils privés. Ajoutez la haute disponibilité ou des règles avancées seulement après avoir documenté le premier flux.

  • Aucune redirection de port vers Unraid ou l’application.
  • cloudflared joint Cloudflare en TCP et UDP 7844.
  • Le jeton n’apparaît ni dans la commande, ni dans un dépôt, ni dans un modèle partagé.
  • cloudflared et l’origine partagent un chemin réseau précis.
  • L’URL de service utilise le bon protocole et le bon port.
  • La politique Access autorise seulement les identités prévues.
  • Le MFA et l’authentification propre à l’application restent actifs.
  • Les clients mobiles, API, WebSockets et webhooks sont testés séparément.
  • Un VPN ou autre accès privé permet encore d’administrer Unraid.
  • La rotation du jeton, la mise à jour et le retrait d’une route sont documentés.