Plan de l'article
đĄ En rĂ©sumĂ© (TL;DR)
- On parle encore de « certificat SSL », mais le protocole moderne est TLS. Le certificat relie un nom de domaine à une clé publique et permet au client de vérifier le serveur.
- Pour une application Node.js sur VPS, la solution la plus simple est généralement de terminer TLS dans un reverse proxy comme Caddy, puis de joindre Node.js sur une interface privée.
- Let's Encrypt valide le contrĂŽle du domaine via ACME. HTTP-01 exige que le domaine atteigne le serveur ; DNS-01 publie un TXT et permet les certificats wildcard.
- Le renouvellement doit ĂȘtre automatique et surveillĂ©. Tester seulement l'Ă©mission initiale ne suffit pas.
- Le verdict AngleFormation : gardez Node.js non exposĂ©, utilisez un proxy maintenu, faites confiance uniquement aux bons en-tĂȘtes proxy et vĂ©rifiez HTTPS depuis l'extĂ©rieur.
Un certificat expiré rend un site inaccessible ou déclenche un avertissement. Un proxy mal configuré peut provoquer des boucles de redirection, des cookies non sécurisés ou une fausse adresse client. Mettre HTTPS en production demande donc plus que l'obtention d'un fichier.
Ce guide présente une architecture simple pour un site Node.js ou Express déployé en Docker sur un VPS.
SSL, TLS, HTTPS et ACME
| Terme | RĂŽle |
|---|---|
| TLS | protocole de chiffrement et d'authentification |
| HTTPS | HTTP transporté dans TLS |
| Certificat | associe identité, clé publique, domaines et validité |
| ACME | protocole d'automatisation de l'émission et du renouvellement |
| Let's Encrypt | autorité de certification publique utilisant ACME |
| Reverse proxy | reçoit le trafic puis le transmet à l'application |
SNI permet Ă plusieurs domaines d'utiliser la mĂȘme adresse avec des certificats diffĂ©rents. ALPN aide le client et le serveur Ă nĂ©gocier le protocole, par exemple HTTP/2. Node.js documente ces fonctions dans son module TLS.
Ătape 1 â VĂ©rifier DNS et rĂ©seau
Avant toute émission :
- le domaine A ou AAAA doit pointer vers le bon serveur ;
- l'IPv6 publiée doit fonctionner ;
- les ports 80 et 443 doivent atteindre le proxy ;
- aucun autre service ne doit occuper ces ports ;
- le pare-feu de l'hébergeur et celui du VPS doivent les autoriser ;
- l'heure du serveur doit ĂȘtre correcte.
Vérifications :
dig A app.exemple.fr
dig AAAA app.exemple.fr
curl -I http://app.exemple.fr/
ss -lntp
Pour HTTP-01, Let's Encrypt recommande de laisser le port 80 accessible et de rediriger les requĂȘtes ordinaires vers HTTPS. Si le site ne peut pas exposer le port 80 ou nĂ©cessite un wildcard, utilisez DNS-01 avec une automatisation DNS sĂ©curisĂ©e.
Ătape 2 â Choisir oĂč terminer TLS
Option recommandée : reverse proxy
Le proxy :
- écoute sur 80 et 443 ;
- obtient et renouvelle les certificats ;
- redirige HTTP vers HTTPS ;
- applique les en-tĂȘtes ;
- transmet vers Node.js en privé.
Node.js peut aussi servir directement HTTPS avec le module node:https, mais l'application doit alors charger les clés, gérer le rechargement et les renouvellements. Pour plusieurs services, le proxy central est souvent plus simple.
Ătape 3 â DĂ©ployer Node.js sans exposition publique
Compose minimal :
services:
app:
build: .
restart: unless-stopped
environment:
NODE_ENV: production
PORT: "3000"
ports:
- "127.0.0.1:3000:3000"
Le port Ă©coute seulement sur la boucle locale de l'hĂŽte. Si Caddy est lui-mĂȘme dans Docker, n'utilisez pas localhost pour joindre un autre conteneur : Caddy rappelle que localhost dĂ©signe son propre conteneur. Placez les services sur un rĂ©seau Docker et utilisez le nom du service.
Ătape 4 â Configurer Caddy
Sur l'hĂŽte :
app.exemple.fr {
encode zstd gzip
reverse_proxy 127.0.0.1:3000
}
Avec un nom public valide, Caddy active automatiquement HTTPS, obtient un certificat et gÚre son renouvellement. Il redirige aussi HTTP vers HTTPS selon ses valeurs par défaut.
Avant le rechargement :
caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy
sudo journalctl -u caddy --since "10 minutes ago"
Les commandes supposent une installation systĂšme Caddy. Utilisez les chemins et droits de votre environnement.
Caddy et Docker sur le mĂȘme rĂ©seau
services:
caddy:
image: caddy:2
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
- caddy_config:/config
networks: [web]
app:
build: .
restart: unless-stopped
expose:
- "3000"
networks: [web]
volumes:
caddy_data:
caddy_config:
networks:
web:
Caddyfile :
app.exemple.fr {
reverse_proxy app:3000
}
Les volumes Caddy doivent ĂȘtre persistants. Ne supprimez pas leur contenu pendant une mise Ă jour ordinaire.
Ătape 5 â Configurer Express derriĂšre le proxy
Express utilise trust proxy pour interprĂ©ter l'adresse client et le protocole transmis. La documentation avertit que la valeur true est dangereuse si le dernier proxy ne remplace pas correctement les en-tĂȘtes.
Si le proxy est local :
import express from "express";
const app = express();
app.set("trust proxy", "loopback");
app.get("/health", (req, res) => {
res.json({
ok: true,
protocol: req.protocol
});
});
app.listen(3000, "0.0.0.0");
Adaptez la liste de confiance Ă votre topologie exacte. S'il existe plusieurs chemins rĂ©seau, une simple profondeur en nombre de sauts peut ĂȘtre contournĂ©e.
Cookies
En production :
- Secure pour envoyer uniquement sur HTTPS ;
- HttpOnly pour réduire l'accÚs JavaScript ;
- SameSite selon le flux d'authentification ;
- domaine et chemin minimaux ;
- rotation de session.
Le proxy de confiance doit ĂȘtre correct pour qu'Express reconnaisse HTTPS et applique les cookies comme prĂ©vu.
Ătape 6 â Choisir le dĂ©fi ACME
| Défi | Fonctionnement | à choisir quand |
|---|---|---|
| HTTP-01 | fichier temporaire servi sur HTTP | site public simple, port 80 accessible |
| DNS-01 | TXT sous _acme-challenge | wildcard, serveurs multiples, port 80 indisponible |
DNS-01 demande des droits sur la zone DNS. Créez un jeton limité à la zone et aux opérations nécessaires. Ne donnez pas une clé globale au serveur si le fournisseur permet une portée plus restreinte.
Pour de nombreux frontends, Let's Encrypt explique que DNS-01 peut ĂȘtre plus facile, mais la propagation du TXT doit ĂȘtre prise en compte.
Ătape 7 â Tester HTTPS
Depuis une autre machine :
curl -I http://app.exemple.fr/
curl -I https://app.exemple.fr/
openssl s_client -connect app.exemple.fr:443 -servername app.exemple.fr </dev/null
Vérifiez :
- redirection HTTP vers HTTPS ;
- nom de domaine présent dans le certificat ;
- chaĂźne de certification ;
- dates de validité ;
- aucun contenu mixte ;
- cookie Secure ;
- bonnes URL canoniques ;
- absence de boucle ;
- WebSocket si l'application l'utilise.
Testez depuis Internet et pas uniquement depuis le VPS.
Renouvellement et supervision
Un client ACME fiable renouvelle avant expiration. Ajoutez une alerte indépendante qui vérifie :
- jours restants ;
- statut HTTPS ;
- nom couvert ;
- erreurs du proxy ;
- échec répété de validation ;
- espace disque du volume de certificats.
Ăvitez de redemander sans cesse un nouveau certificat lors d'un test : Let's Encrypt applique des limites. Utilisez l'environnement de staging pour les essais de configuration et lisez les limites actuelles.
Ne dépendez pas d'une durée fixe dans vos procédures. Let's Encrypt propose plusieurs profils de durée et fait évoluer son infrastructure ; l'automatisation et la surveillance sont la bonne réponse.
Cas Cloudflare ou autre CDN
Lorsqu'un CDN se place devant le VPS, deux connexions existent :
- navigateur vers CDN ;
- CDN vers origine.
Chiffrez les deux. Ăvitez un mode qui accepte HTTP non authentifiĂ© vers l'origine. Limitez l'accĂšs direct au VPS si possible, mais assurez-vous que le mĂ©canisme ACME choisi continue de fonctionner.
Le certificat vu par le navigateur peut ĂȘtre celui du CDN, tandis que l'origine possĂšde un certificat distinct.
En-tĂȘtes de sĂ©curitĂ©
Le proxy ou l'application peut ajouter :
- HSTS aprĂšs validation complĂšte de HTTPS ;
- Content-Security-Policy adaptée au site ;
- X-Content-Type-Options ;
- Referrer-Policy ;
- Permissions-Policy.
N'activez pas HSTS avec une longue durée ou includeSubDomains avant de confirmer que tous les sous-domaines fonctionnent en HTTPS. Une erreur HSTS peut bloquer l'accÚs durablement cÎté navigateur.
Diagnostic des erreurs
Validation ACME échoue
- DNS pointe vers l'ancienne IP ;
- IPv6 incorrecte ;
- port 80 bloqué ;
- proxy non démarré ;
- WAF intercepte le challenge ;
- TXT DNS-01 non propagé ;
- limite d'émission atteinte.
Boucle de redirection
- l'application ne fait pas confiance au bon proxy ;
- le proxy transmet un protocole incorrect ;
- plusieurs couches redirigent contradictoirement ;
- une variable d'URL publique est en HTTP.
Mauvaise IP client
- trust proxy absent ou trop large ;
- en-tĂȘte transmis sans ĂȘtre nettoyĂ© ;
- proxy supplémentaire non documenté.
Certificat expiré
- tĂąche de renouvellement arrĂȘtĂ©e ;
- volume non persistant ;
- changement DNS ;
- permissions ;
- client ACME ou proxy obsolĂšte.
Checklist de production
- A/AAAA corrects ;
- ports 80/443 maßtrisés ;
- application non exposée publiquement ;
- proxy et images épinglés ;
- certificat valide ;
- renouvellement automatique ;
- alerte avant expiration ;
- proxy de confiance précis ;
- cookies sécurisés ;
- HSTS activé seulement aprÚs validation ;
- sauvegarde de configuration ;
- procédure de rollback ;
- test aprĂšs chaque changement DNS ou proxy.
FAQ
Let's Encrypt est-il gratuit ?
Oui pour l'émission publique, mais l'exploitation du serveur et l'automatisation restent à votre charge. Respectez ses limites et utilisez un client ACME maintenu.
Faut-il copier le certificat dans le conteneur Node.js ?
Pas si le reverse proxy termine TLS et joint Node.js sur un réseau privé. Cette architecture simplifie les renouvellements et évite de partager la clé avec l'application.
Comment obtenir un wildcard ?
Let's Encrypt exige le défi DNS-01 pour un wildcard. Automatisez la création du TXT avec un jeton DNS limité.
Peut-on fermer le port 80 aprÚs émission ?
Si vous utilisez HTTP-01, il reste nécessaire pour les validations et renouvellements. Let's Encrypt recommande de garder 80 ouvert pour le web et de rediriger vers HTTPS. DNS-01 suit une autre logique.
Conclusion
Le meilleur certificat est celui dont l'émission, le renouvellement et le diagnostic sont automatisés. Pour Node.js et Docker, un reverse proxy comme Caddy réduit la complexité : l'application reste privée, le proxy gÚre TLS et la configuration Express reflÚte précisément la topologie.
Pour choisir l'hébergement, consultez notre comparatif de VPS backend et notre pilier Tech-Cloud.