Pourquoi un reverse proxy sur VPS
Un VPS expose une seule adresse IP publique. Si vous faites tourner trois applications Docker — une API, un front-end et un outil d'administration — chacune occupe un port différent : 3000, 8080, 9000. Sans reverse proxy, vos visiteurs doivent taper le port dans l'URL, les certificats SSL doivent être gérés application par application, et ouvrir tous ces ports au public augmente la surface d'attaque.
Un reverse proxy centralise l'entrée du trafic : il reçoit toutes les requêtes sur les ports 80 et 443, inspecte le nom de domaine ou le chemin, puis transmet la requête au bon conteneur sur le réseau interne. Les applications n'exposent plus de ports publics. Le SSL se termine au niveau du proxy, qui redistribue en HTTP simple sur le réseau Docker privé.
Cette architecture offre trois avantages concrets : un seul point de gestion des certificats, une isolation réseau des applications, et la possibilité d'ajouter ou de retirer une app sans toucher aux autres.
Ce que Nginx Proxy Manager simplifie
- Interface web : ajout, modification et suppression d'hôtes proxy sans ligne de commande ni rechargement manuel
- SSL Let's Encrypt en un clic : NPM demande, renouvelle et déploie les certificats automatiquement via HTTP-01 ou DNS-01
- Wildcard DNS : un seul certificat pour
*.mondomaine.comsi votre fournisseur DNS supporte l'API Certbot - Listes d'accès : authentification HTTP basique ou IP whitelisting directement depuis l'interface
- Redirections et URLs personnalisées : HTTP vers HTTPS, redirections 301/302, sans modifier nginx.conf
- Rechargement sans interruption : NPM recharge la configuration nginx en arrière-plan, sans downtime
Prérequis
Pour suivre ce guide, vous avez besoin d'un VPS sous Ubuntu 22.04 ou Debian 12 avec au minimum 1 Go de RAM (2 Go recommandés si plusieurs apps tournent simultanément). Docker Engine et Docker Compose v2 doivent être installés.
Les ports 80 et 443 doivent être accessibles depuis l'extérieur. Vérifiez que votre pare-feu (ufw ou règles du panneau de contrôle) les autorise. Si vous utilisez un pare-feu cloud (groupe de sécurité, firewall VPS), ouvrez ces deux ports en entrée.
Enfin, vous devez posséder au moins un nom de domaine ou sous-domaine pointant vers l'IP de votre VPS. NPM peut gérer plusieurs domaines simultanément — le prérequis minimal est qu'un enregistrement DNS A existe pour chaque domaine que vous souhaitez proxifier.
Installer NPM avec Docker Compose
Créer la structure de répertoires
Créez un dossier dédié et placez-vous dedans :
mkdir -p /opt/npm && cd /opt/npmCe dossier contiendra le fichier Compose et les volumes persistants de NPM (base de données SQLite, certificats, logs).
Rédiger docker-compose.yml
Créez le fichier
/opt/npm/docker-compose.ymlavec le contenu suivant :services: app: image: jc21/nginx-proxy-manager:latest restart: unless-stopped ports: - "80:80" - "443:443" - "81:81" volumes: - ./data:/data - ./letsencrypt:/etc/letsencrypt networks: default: name: proxy-net external: falseLe port
81est l'interface d'administration. Le réseauproxy-netsera partagé avec vos autres conteneurs pour qu'ils soient joignables sans exposer de ports publics.Démarrer NPM
Lancez le conteneur en arrière-plan :
docker compose up -dPatientez 30 à 60 secondes le temps que NPM initialise sa base de données. Vérifiez que les trois ports sont bien en écoute :
ss -tlnp | grep -E ':(80|81|443)'Première connexion et changement de mot de passe
Ouvrez
http://IP_DE_VOTRE_VPS:81dans votre navigateur. Les identifiants par défaut sont[email protected]/changeme.NPM vous force à changer l'adresse e-mail et le mot de passe à la première connexion. Utilisez une adresse valide : elle sera utilisée pour les notifications d'expiration de certificat Let's Encrypt.
Attention : le port 81 est exposé publiquement. Configurez immédiatement une liste d'accès (voir section "Access Lists") ou filtrez ce port au niveau du pare-feu pour le restreindre à votre IP.
Ajouter un premier hôte proxy
Créer un nouvel hôte proxy
Dans l'interface NPM, cliquez sur Proxy Hosts puis Add Proxy Host. Remplissez le champ Domain Names avec votre domaine, par exemple
app.mondomaine.com. Assurez-vous que l'enregistrement DNS A de ce sous-domaine pointe déjà vers l'IP de votre VPS — Let's Encrypt vérifiera cette résolution.Configurer la destination
Dans les champs Forward Hostname / IP et Forward Port, indiquez l'hôte et le port de votre application. Si l'application tourne dans un conteneur Docker sur le même réseau
proxy-net, utilisez le nom du service Docker comme hostname (exemple :monappet port3000). Cochez Block Common Exploits pour activer les règles de filtrage basiques.Activer Let's Encrypt
Passez dans l'onglet SSL de la même fenêtre. Dans le menu déroulant, sélectionnez Request a new SSL Certificate. Cochez Force SSL pour rediriger automatiquement HTTP vers HTTPS, et HTTP/2 Support pour activer HTTP/2. Renseignez votre adresse e-mail, acceptez les conditions Let's Encrypt, puis cliquez Save.
NPM lance immédiatement la demande de certificat via le challenge HTTP-01. En moins d'une minute, votre domaine est accessible en HTTPS avec un certificat valide.
Vérifier le résultat
La liste des hôtes proxy affiche maintenant votre entrée avec un badge SSL vert. Testez depuis votre navigateur ou avec curl :
curl -I https://app.mondomaine.comLa réponse doit contenir
HTTP/2 200et un en-têteserver: nginx. Le renouvellement du certificat est automatique — NPM relance la demande 30 jours avant l'expiration.
Configurer un sous-domaine avec redirection HTTPS forcée
Forcer HTTPS n'est pas qu'une bonne pratique : c'est la base de la sécurité transport. Lors de la création ou de l'édition d'un hôte proxy, l'onglet SSL expose trois options complémentaires.
Force SSL : NPM génère automatiquement un bloc return 301 https://$host$request_uri; dans la configuration nginx du vhost. Toute requête HTTP est redirigée côté serveur avant même d'atteindre votre application.
HSTS (HTTP Strict Transport Security) : en cochant cette option, NPM ajoute l'en-tête Strict-Transport-Security: max-age=63072000; includeSubDomains; preload aux réponses HTTPS. Le navigateur mémorise que ce domaine doit toujours être contacté en HTTPS, même si l'utilisateur tape http://. Activez HSTS uniquement si vous êtes certain de maintenir le SSL — désactiver HSTS après coup n'a aucun effet immédiat sur les navigateurs qui l'ont déjà mis en cache.
HTTP/2 Support : active le protocole HTTP/2 côté client, sans modification côté application. Le multiplexage réduit la latence perçue, notamment sur les pages avec de nombreuses ressources.
Cas avancé : proxy pour une app Docker sans port exposé
L'un des avantages les plus sous-estimés de NPM est la capacité de proxifier des conteneurs qui n'exposent aucun port public. La communication se fait uniquement sur le réseau Docker interne.
Pour qu'un conteneur soit joignable par NPM sans exposition publique, les deux services doivent partager le même réseau Docker. Exemple avec une app Node.js dans /opt/monapp/docker-compose.yml :
services:
web:
image: mon-image:latest
restart: unless-stopped
# Pas de section 'ports' — le conteneur n'est pas accessible depuis l'hôte
networks:
- proxy-net
networks:
proxy-net:
external: trueEn déclarant proxy-net comme réseau externe et en rattachant le service à ce réseau, le conteneur web devient joignable depuis NPM par son nom de service. Dans l'interface NPM, Forward Hostname sera simplement web et Forward Port le port interne de l'app (par exemple 3000).
Cette architecture signifie que même si un attaquant compromet un conteneur, il ne peut pas atteindre les autres services directement depuis l'extérieur — tout passe par le proxy.
Access Lists : protéger le backoffice avec une authentification
NPM permet de restreindre l'accès à certains hôtes proxy via des listes d'accès. Allez dans Access Lists puis Add Access List. Donnez un nom à la liste, ajoutez des entrées sous l'onglet Authorization (nom d'utilisateur + mot de passe hashé), et/ou restreignez par IP sous Access.
Ensuite, éditez l'hôte proxy que vous souhaitez protéger et sélectionnez cette liste dans le champ Access List. NPM injecte automatiquement un bloc auth_basic dans la configuration nginx du vhost. C'est particulièrement utile pour exposer des outils d'administration (Portainer, Grafana, interfaces d'API internes) sans déployer un serveur d'authentification complet.
Pour le port 81 lui-même (l'interface NPM), la protection passe par le pare-feu — restreignez l'accès à ce port à votre IP fixe ou à un VPN.
Comparatif : Nginx Proxy Manager vs Caddy vs Traefik
Faites défiler le tableau
| Critère | Nginx Proxy Manager | Caddy | Traefik |
|---|---|---|---|
| Configuration | Interface web graphique, zéro fichier à éditer | Caddyfile déclaratif, syntaxe concise | YAML/TOML ou labels Docker, courbe d'apprentissage plus longue |
| SSL automatique | Let's Encrypt HTTP-01 et DNS-01, interface graphique | Intégré nativement, HTTP-01 et DNS-01 sans plugin | ACME intégré, nécessite configuration YAML |
| Auto-découverte Docker | Non, configuration manuelle par hôte | Non natif, possible via labels avec caddy-docker-proxy | Natif via labels Docker, détecte les services au démarrage |
| Cas d'usage idéal | Développeur gérant < 20 apps, préfère l'UI à la config | Stack simple à moyenne, config lisible en fichier | Microservices, Kubernetes, environnements dynamiques |
| Personnalisation avancée | Limitée — snippets nginx personnalisés possibles mais non recommandés | Élevée via modules et Caddyfile directives | Très élevée, middlewares chaînables, plugins riches |
| Ressources | ~50 Mo RAM au repos | ~30 Mo RAM au repos | ~40 Mo RAM au repos, plus selon plugins |
Limites de NPM et quand migrer vers Traefik
NPM couvre la grande majorité des cas d'usage des développeurs qui gèrent une dizaine d'applications sur un ou deux VPS. Il commence à montrer ses limites dans plusieurs scénarios.
Configuration avancée nginx : NPM génère ses fichiers de configuration et les régénère à chaque modification depuis l'interface. Il est techniquement possible d'ajouter des snippets personnalisés, mais ils peuvent être écrasés lors d'une mise à jour. Si vous avez besoin de configurations nginx fines — rate limiting par route, cache proxy complexe, logique de réécriture avancée — NPM devient une couche de friction plutôt qu'une aide.
Environnements dynamiques : dans une architecture microservices où des conteneurs apparaissent et disparaissent fréquemment, la configuration manuelle de chaque hôte dans NPM devient un goulot d'étranglement. HAProxy ou Traefik, qui détectent automatiquement les services via les labels Docker, sont mieux adaptés à ce contexte.
Kubernetes : NPM n'a pas de place dans un cluster Kubernetes. Traefik dispose d'un Ingress Controller natif ; ingress-nginx est l'autre option courante.
Règle pratique : si votre configuration tient dans l'interface NPM et ne nécessite pas de scripts d'automatisation pour rester à jour, NPM est le bon choix. Dès que vous vous retrouvez à écrire des scripts pour interagir avec l'API NPM ou à gérer des fichiers de configuration en dehors de l'interface, c'est le signal pour évaluer Caddy ou Traefik selon votre contexte.