🤔 Le problème : exposer un service sans se mettre en danger
Quand vous lancez une application sur un VPS (une API FastAPI sur le port 8000, un dashboard admin sur le port 3000, un webhook sur le port 5000…), elle n'est accessible que localement.
Pour la rendre accessible depuis Internet, la méthode classique consiste à :
- Ouvrir le port dans le firewall (UFW, iptables…)
- Configurer un reverse proxy (Nginx, Caddy…)
- Obtenir un certificat SSL (Let's Encrypt…)
- Gérer le renouvellement du certificat
- Se protéger contre les attaques DDoS
Chaque étape ajoute de la complexité et des risques :
| Risque | Description |
|---|---|
| Ports ouverts | Chaque port ouvert est une surface d'attaque potentielle |
| Mauvaise config Nginx | Headers manquants, TLS mal configuré, fuite d'infos serveur |
| Certificat expiré | Service inaccessible, erreurs navigateur |
| DDoS | Un VPS standard ne résiste pas à une attaque volumétrique |
| Scan de ports | Les bots scannent en permanence les IP publiques |
Et si vous pouviez tout éviter ?
🚀 La solution : Cloudflare Tunnel (ex-Argo Tunnel)
Cloudflare Tunnel crée une connexion sortante depuis votre serveur vers le réseau Cloudflare. Aucun port entrant n'est nécessaire.
⚙️ Comment ça marche
[Utilisateur] → [Cloudflare Edge] ← tunnel chiffré ← [cloudflared sur votre VPS] → [localhost:8000]
Le flux est inversé par rapport à un serveur classique :
cloudflared(le client tunnel) tourne sur votre VPS- Il établit une connexion sortante vers Cloudflare
- Cloudflare route le trafic entrant vers votre tunnel
- Votre service reste sur
localhost— aucun port ouvert
✅ Avantages
| Feature | Classique (Nginx + Let's Encrypt) | Cloudflare Tunnel |
|---|---|---|
| Ports à ouvrir | 80, 443 + ports services | Aucun (0) |
| SSL | Let's Encrypt (config manuelle) | Automatique |
| Protection DDoS | Aucune (ou payante) | Incluse gratuitement |
| Reverse proxy | Nginx/Caddy à configurer | Intégré |
| Difficulté | Intermédiaire à avancé | Débutant à intermédiaire |
| Coût | Gratuit | Gratuit |
| Zero Trust | Non | Oui (Access policies) |
🛠️ Prérequis
Avant de commencer, vous aurez besoin de :
- Un VPS avec Linux (Ubuntu/Debian recommandé) — Hostinger propose d'excellents VPS à partir de 3,99€/mois avec 20% de remise
- Un nom de domaine pointé vers Cloudflare (nameservers Cloudflare)
- Un compte Cloudflare (gratuit)
- Un service local qui tourne (API, site, dashboard…)
💡 Astuce VPS : Pour un tunnel Cloudflare, même un petit VPS suffit.
cloudflaredconsomme très peu de ressources (~20 Mo de RAM). Hostinger est idéal pour débuter avec un excellent rapport qualité/prix.
📥 Étape 1 : Installer cloudflared
🐧 Sur Ubuntu/Debian
L'installation sur Ubuntu/Debian se fait via le dépôt officiel Cloudflare : on ajoute la clé GPG, puis le dépôt, et on installe le paquet cloudflared avec apt. Cette méthode garantit des mises à jour automatiques.
✔️ Vérifier l'installation
cloudflared --version
📦 Alternative : binaire direct
Si le dépôt pose problème, vous pouvez télécharger le binaire officiel depuis les releases GitHub et le placer dans /usr/local/bin/ avec les droits d'exécution.
🔐 Étape 2 : Authentification
Connectez-vous à votre compte Cloudflare en exécutant la commande cloudflared tunnel login. Cette commande ouvre un lien dans le terminal : copiez-le dans votre navigateur, sélectionnez le domaine à utiliser, et autorisez. Un certificat sera sauvegardé dans ~/.cloudflared/cert.pem. Vous pouvez vérifier sa présence avec la commande ls -la ~/.cloudflared/cert.pem.
🏗️ Étape 3 : Créer le tunnel
Exécutez la commande cloudflared tunnel create mon-tunnel. Elle génère un UUID unique pour le tunnel et sauvegarde les credentials dans un fichier JSON. Notez cet UUID, vous en aurez besoin pour la configuration. Listez ensuite vos tunnels avec cloudflared tunnel list pour vérifier que tout est en ordre.
⚙️ Étape 4 : Configurer le tunnel
Créez le fichier de configuration avec la commande nano ~/.cloudflared/config.yml.
📝 Configuration simple (un seul service)
tunnel: a1b2c3d4-e5f6-7890-abcd-ef1234567890
credentials-file: /root/.cloudflared/a1b2c3d4-e5f6-7890-abcd-ef1234567890.json
ingress:
- hostname: api.mondomaine.com
service: http://localhost:8000
- service: http_status:404
🔀 Configuration multi-services
Pour plusieurs services, on ajoute une entrée ingress par hostname, chacune pointant vers un port local différent. On peut aussi ajouter des options originRequest comme connectTimeout ou noTLSVerify selon les besoins de chaque service. La dernière entrée doit toujours être un catch-all http_status:404 sans hostname — c'est obligatoire.
✅ Valider la configuration
cloudflared tunnel ingress validate
🌐 Étape 5 : Configurer le DNS
Pour chaque hostname dans votre config, créez un enregistrement DNS CNAME automatiquement avec la commande cloudflared tunnel route dns mon-tunnel api.mondomaine.com (à répéter pour chaque sous-domaine). Cela crée automatiquement des enregistrements CNAME dans votre zone Cloudflare, tous pointant vers l'adresse cfargotunnel.com de votre tunnel avec le proxy activé.
▶️ Étape 6 : Lancer le tunnel
🧪 Test manuel
Lancez le tunnel avec la commande cloudflared tunnel run mon-tunnel. Si le tunnel est opérationnel, vous verrez 4 connexions enregistrées dans les logs. Testez ensuite dans votre navigateur : https://api.mondomaine.com
🏭 En tant que service systemd (production)
Pour que le tunnel démarre automatiquement au boot, installez-le en tant que service systemd via sudo cloudflared service install. Le service utilise la config située dans /etc/cloudflared/config.yml — pensez à y copier votre fichier de configuration et vos credentials JSON. Activez-le ensuite avec sudo systemctl enable cloudflared.
🐍 Cas d'usage 1 : Exposer une API FastAPI
Imaginons que vous développez une API IA avec FastAPI. L'application expose un endpoint /health pour le monitoring et un endpoint /generate pour les requêtes IA, acceptant un prompt et un paramètre max_tokens.
Lancez l'API sur localhost avec la commande uvicorn api:app --host 127.0.0.1 --port 8000.
Configuration tunnel adaptée aux services IA :
ingress:
- hostname: api.mondomaine.com
service: http://localhost:8000
originRequest:
connectTimeout: 30s # Plus long pour les requêtes IA
- service: http_status:404
Votre API est maintenant accessible sur https://api.mondomaine.com avec SSL automatique ! Testez avec un curl vers /health ou /generate depuis n'importe où.
📊 Cas d'usage 2 : Dashboard admin protégé
Pour un dashboard admin (Streamlit, Grafana, ou custom), vous voulez une couche d'authentification supplémentaire.
Cloudflare Access (Zero Trust)
Cloudflare offre gratuitement (jusqu'à 50 utilisateurs en 2025) un système d'authentification. Depuis le dashboard Zero Trust → Access → Applications, créez une application de type Self-hosted, indiquez le subdomain admin.mondomaine.com, et définissez une policy autorisant uniquement votre email.
Maintenant, quand quelqu'un accède à admin.mondomaine.com, il doit d'abord s'authentifier via Cloudflare Access. Même si votre dashboard n'a pas de login, il est protégé.
# config.yml - le dashboard est sur localhost:8501 (Streamlit)
ingress:
- hostname: admin.mondomaine.com
service: http://localhost:8501
originRequest:
noTLSVerify: true
- service: http_status:404
Vérifier le header JWT dans votre app
Cloudflare Access ajoute un header Cf-Access-Jwt-Assertion à chaque requête. Vous pouvez le vérifier côté serveur en récupérant le token, en téléchargeant les clés publiques depuis l'endpoint /cdn-cgi/access/certs de votre team Cloudflare, puis en décodant le JWT avec l'algorithme RS256 en vérifiant l'audience correspondant à votre URL.
🔗 Cas d'usage 3 : Webhook receiver
Les webhooks (GitHub, Stripe, Telegram…) nécessitent une URL publique HTTPS. Cloudflare Tunnel est parfait pour ça. Côté application, il suffit de récupérer le body de la requête, de vérifier la signature (par exemple X-Hub-Signature-256 pour GitHub avec HMAC-SHA256), puis de traiter l'événement.
ingress:
- hostname: webhook.mondomaine.com
service: http://localhost:5000
originRequest:
connectTimeout: 10s
- service: http_status:404
🔒 Sécurité avancée : verrouiller votre VPS
Maintenant que tout passe par Cloudflare Tunnel, vous pouvez fermer tous les ports sauf SSH en utilisant UFW : refusez tout le trafic entrant par défaut, autorisez le trafic sortant, ouvrez uniquement le port 22 en TCP, puis activez le firewall.
Votre VPS n'a plus qu'un seul port ouvert : SSH. Tout le reste passe par le tunnel.
Aller plus loin : restreindre SSH aussi
Vous pouvez restreindre SSH à votre IP only avec sudo ufw allow from VOTRE_IP to any port 22 proto tcp, ou même faire passer SSH via le tunnel Cloudflare en ajoutant une règle ssh://localhost:22 dans votre config ingress. Côté client, configurez votre ~/.ssh/config avec ProxyCommand cloudflared access ssh --hostname %h pour vous connecter via le tunnel.
🔍 Monitoring et debugging
Vérifier l'état du tunnel
Utilisez sudo systemctl status cloudflared pour le statut du service, sudo journalctl -u cloudflared -f pour les logs en temps réel, et cloudflared tunnel info mon-tunnel pour les métriques détaillées.
Logs détaillés
Pour lancer le tunnel en mode debug, ajoutez l'option --loglevel debug ou ajoutez loglevel: debug dans votre config.yml.
🔧 Configuration avancée
Timeouts et performances
Ajustez les timeouts selon le type de service dans la section originRequest de chaque règle ingress. Par exemple : 10 secondes pour une API classique, 120 secondes pour un service IA avec réponses lentes ou streaming, 5 secondes pour des fichiers statiques. Les WebSockets sont supportés nativement sans configuration supplémentaire.
Headers personnalisés
Cloudflare ajoute automatiquement des headers utiles à chaque requête : Cf-Connecting-Ip (IP réelle du visiteur), X-Forwarded-For, et X-Forwarded-Proto. Côté application, vous pouvez récupérer l'IP réelle et le pays du visiteur directement depuis ces headers.
Métriques et observabilité
Activez les métriques Prometheus en ajoutant metrics: localhost:2000 au niveau racine de votre config. Vous obtiendrez alors des métriques comme le nombre total de requêtes, les erreurs, les requêtes concurrentes, les réponses par code HTTP et la latence.
🐛 Troubleshooting avancé
Diagnostic étape par étape
Quand quelque chose ne marche pas, suivez cet arbre de décision :
- 502 Bad Gateway → Vérifiez que le service local tourne (
curl http://localhost:PORT), que le port est correct dans config.yml, et ajouteznoTLSVerify: truesi le service est en HTTPS local. - ERR_NAME_NOT_RESOLVED → Le DNS n'est pas configuré. Vérifiez avec
diget relancezcloudflared tunnel route dns. - ERR_CONNECTION_TIMED_OUT → Le tunnel ne tourne pas, les credentials sont invalides, ou le firewall bloque le trafic sortant vers
*.cloudflare.com. - 1033: Argo Tunnel error → Le tunnel n'existe plus. Vérifiez avec
cloudflared tunnel listet recréez-le si nécessaire. - Access denied (avec Cloudflare Access) → Vérifiez que votre email est dans la policy et que le cookie n'est pas expiré.
Commandes de diagnostic utiles
Les commandes essentielles pour diagnostiquer : cloudflared tunnel run --loglevel debug pour les logs de connexion, dig +short pour vérifier le DNS, curl -v pour tester le service local, ss -tlnp pour les connexions actives, journalctl pour les logs système, et cloudflared tunnel ingress validate pour valider la config.
Problèmes fréquents et solutions
Le tunnel se déconnecte régulièrement
Vérifiez la stabilité réseau avec un ping prolongé. Le service systemd redémarre automatiquement le tunnel en cas de crash. Pour plus de sécurité, vous pouvez ajouter un script de monitoring en cron (toutes les 5 minutes) qui vérifie l'état du service et le redémarre si nécessaire, avec une alerte optionnelle via Telegram.
Latence élevée sur les requêtes
Vérifiez le datacenter Cloudflare utilisé avec curl -s https://api.mondomaine.com/cdn-cgi/trace | grep colo. Si le datacenter est éloigné géographiquement, c'est un problème de routage Cloudflare.
Migration vers un nouveau serveur
Pour migrer, copiez simplement le cert.pem, les fichiers JSON de credentials et le config.yml vers le nouveau serveur dans ~/.cloudflared/. Installez le service avec sudo cloudflared service install et démarrez-le. Aucune modification DNS n'est nécessaire — le tunnel reprend automatiquement sur le nouveau serveur.
📋 Sommaire
- Le problème : exposer un service sans se mettre en danger
- La solution : Cloudflare Tunnel
- Prérequis
- Étape 1 : Installer cloudflared
- Étape 2 : Authentification
- Étape 3 : Créer le tunnel
- Étape 4 : Configurer le tunnel
- Étape 5 : Configurer le DNS
- Étape 6 : Lancer le tunnel
- Cas d'usage 1 : Exposer une API FastAPI
- Cas d'usage 2 : Dashboard admin protégé
- Cas d'usage 3 : Webhook receiver
- Sécurité avancée : verrouiller votre VPS
- Monitoring et debugging
- Configuration avancée
- Troubleshooting avancé
- Récapitulatif : la checklist complète
- Astuces et bonnes pratiques
- Cloudflare Tunnel vs alternatives
- Erreurs courantes
- Outils recommandés
- FAQ
- Conclusion
📋 Récapitulatif : la checklist complète
- ✅ 1. VPS avec Linux (Hostinger recommandé)
- ✅ 2. Domaine pointé vers Cloudflare (nameservers)
- ✅ 3. cloudflared installé
- ✅ 4. Authentification (cloudflared tunnel login)
- ✅ 5. Tunnel créé (cloudflared tunnel create)
- ✅ 6. config.yml rédigé
- ✅ 7. DNS configuré (cloudflared tunnel route dns)
- ✅ 8. Test manuel réussi
- ✅ 9. Service systemd installé et activé
- ✅ 10. Firewall verrouillé (UFW)
- ✅ 11. Cloudflare Access configuré (optionnel)
💡 Astuces et bonnes pratiques
1. Nommez vos tunnels intelligemment
Préférez des noms explicites comme prod-api-fastapi ou staging-dashboard plutôt que tunnel1.
2. Un tunnel par environnement
Séparez production et staging avec des tunnels distincts pour isoler les environnements.
3. Utilisez les variables d'environnement
Évitez de hardcoder les UUID dans vos scripts — utilisez des variables d'environnement pour le tunnel ID et le chemin des credentials.
4. Surveillez vos tunnels
Dans le dashboard Cloudflare → Zero Trust → Networks → Tunnels, vous pouvez voir l'état de chaque tunnel (Healthy/Degraded/Down), les connexions actives et le trafic en temps réel.
5. Backup de vos credentials
Les fichiers cert.pem et les JSON de credentials sont critiques. Sans eux, vous devrez recréer le tunnel. Faites des sauvegardes régulières.
🆚 Cloudflare Tunnel vs alternatives
| Solution | Ports ouverts | SSL auto | DDoS protection | Coût | Difficulté |
|---|---|---|---|---|---|
| Cloudflare Tunnel | ❌ 0 | ✅ | ✅ | Gratuit | ⭐⭐ |
| Nginx + Let's Encrypt | ✅ 80, 443 | ✅ | ❌ | Gratuit | ⭐⭐⭐ |
| Caddy | ✅ 80, 443 | ✅ | ❌ | Gratuit | ⭐⭐ |
| ngrok | ❌ 0 | ✅ | ❌ | Freemium | ⭐ |
| Tailscale Funnel | ❌ 0 | ✅ | ❌ | Freemium | ⭐⭐ |
Cloudflare Tunnel gagne sur presque tous les critères pour un usage production.
🎯 L'essentiel
- Cloudflare Tunnel crée une connexion sortante chiffrée entre votre VPS et Cloudflare — aucun port entrant à ouvrir
- SSL automatique et protection DDoS sont inclus gratuitement
- La configuration tient en un seul fichier YAML avec des règles
ingresspar hostname - En production, installez
cloudflaredcomme service systemd pour un redémarrage automatique - Une fois le tunnel actif, fermez tous les ports du firewall sauf SSH
- Cloudflare Access (Zero Trust) ajoute une couche d'authentification gratuite pour vos dashboards sensibles
❌ Erreurs courantes
- Oublier le catch-all : la dernière règle ingress doit toujours être
service: http_status:404sans hostname, sinon la configuration est rejetée - Mauvais port dans le service : un
502 Bad Gatewaysignifie presque toujours que l'application n'écoute pas sur le port indiqué dansconfig.yml - Ne pas copier les credentials : après
sudo cloudflared service install, le service lit la config dans/etc/cloudflared/— pensez à y copier votreconfig.ymlet le fichier JSON - HTTPS local sans
noTLSVerify: si votre service local utilise HTTPS, ajouteznoTLSVerify: truedansoriginRequestsinon cloudflared refusera la connexion - DNS non routé : si vous obtenez
ERR_NAME_NOT_RESOLVED, c'est que la commandecloudflared tunnel route dnsn'a pas été exécutée pour le hostname concerné
🔧 Outils recommandés
- cloudflared : le client officiel Cloudflare Tunnel (gratuit, ~20 Mo de RAM)
- UFW : firewall simplifié pour verrouiller votre VPS après setup du tunnel
- systemd : gestionnaire de service pour assurer le redémarrage automatique de cloudflared
- Cloudflare Zero Trust Dashboard : interface web pour configurer les policies Access, surveiller les tunnels et gérer les utilisateurs
- Hostinger : hébergeur VPS recommandé pour ce setup, avec un excellent rapport qualité/prix à partir de 3,99€/mois
❓ FAQ
Cloudflare Tunnel est-il vraiment gratuit ?
Oui, le plan gratuit inclut les tunnels illimités, le SSL automatique et la protection DDoS. La seule limite est sur Cloudflare Access (50 utilisateurs gratuits).
Puis-je utiliser Cloudflare Tunnel sans nom de domaine ?
Non, un domaine configuré avec les nameservers Cloudflare est obligatoire pour créer les enregistrements CNAME vers le tunnel.
Le tunnel ajoute-t-il de la latence ?
Très peu. La latence supplémentaire est généralement inférieure à 10 ms si le datacenter Cloudflare le plus proche est bien routé. Vérifiez avec l'endpoint /cdn-cgi/trace.
Que se passe-t-il si cloudflared crash ?
Le service systemd redémarre automatiquement le processus. Pour une surveillance supplémentaire, ajoutez un script de healthcheck en cron.
Puis-je exposer SSH via le tunnel ?
Oui, avec une règle ssh://localhost:22 dans l'ingress et ProxyCommand cloudflared access ssh --hostname %h côté client. Cela permet de fermer le port 22 dans le firewall.
🎯 Conclusion
Cloudflare Tunnel transforme radicalement la façon d'exposer des services :
- Zéro port ouvert = surface d'attaque minimale
- SSL automatique = plus jamais de certificats expirés
- DDoS protection gratuite = tranquillité d'esprit
- Configuration simple = un fichier YAML et c'est parti
- Zero Trust = authentification moderne incluse
Combiné avec un VPS Hostinger (performant et abordable), vous avez une infrastructure de production solide pour quelques euros par mois. Si vous souhaitez aller plus loin dans l'auto-hébergement de services IA, consultez notre guide VPS + IA : le setup complet pour tout auto-héberger. Pour optimiser vos appels d'API depuis vos services exposés, notre comparatif APIs IA : OpenRouter vs appels directs vous aidera à choisir la bonne approche. Et si vous conteneurisez vos services, Docker + IA : conteneuriser ses services intelligents complète parfaitement ce setup.
```