Node.js dispose d’un support HTTPS intégré via le module https. Vous chargez vos fichiers de certificat et créez un serveur HTTPS. Ce guide couvre Node.js pur, Express et la configuration de production recommandée.
Serveur HTTPS basique
const https = require('https');
const fs = require('fs');
const options = {
key: fs.readFileSync('/etc/ssl/privkey.pem'),
cert: fs.readFileSync('/etc/ssl/fullchain.pem'),
};
https.createServer(options, (req, res) => {
res.writeHead(200);
res.end('Hello HTTPS');
}).listen(443);
Express avec HTTPS
const https = require('https');
const fs = require('fs');
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('Hello HTTPS');
});
const options = {
key: fs.readFileSync('/etc/ssl/privkey.pem'),
cert: fs.readFileSync('/etc/ssl/fullchain.pem'),
};
https.createServer(options, app).listen(443, () => {
console.log('HTTPS server running on port 443');
});
Rediriger HTTP vers HTTPS
Exécutez à la fois un serveur HTTP et un serveur HTTPS :
const http = require('http');
const https = require('https');
const fs = require('fs');
const express = require('express');
const app = express();
// ... vos routes
const options = {
key: fs.readFileSync('/etc/ssl/privkey.pem'),
cert: fs.readFileSync('/etc/ssl/fullchain.pem'),
};
// HTTPS server
https.createServer(options, app).listen(443);
// HTTP redirect
http.createServer((req, res) => {
res.writeHead(301, { Location: `https://${req.headers.host}${req.url}` });
res.end();
}).listen(80);
Recommandation pour la production : reverse proxy
En production, ne terminez pas TLS directement dans Node.js. Utilisez un reverse proxy (Nginx, Caddy ou un load balancer) en amont :
Client ──HTTPS──→ Nginx (terminaison TLS) ──HTTP──→ Node.js (port 3000)
Raisons :
- Nginx gère TLS plus efficacement (C vs JavaScript)
- Le renouvellement des certificats ne nécessite pas de redémarrage de Node.js
- Le port 443 nécessite les droits root — Node.js ne devrait pas s’exécuter en root
- Limitation de débit, mise en cache, compression gérées par le proxy
- HTTP/2 est mieux supporté dans Nginx
Le HTTPS direct dans Node.js convient pour le développement, les services internes ou les petits projets.
Frameworks courants
Fastify
const fastify = require('fastify')({
https: {
key: fs.readFileSync('/etc/ssl/privkey.pem'),
cert: fs.readFileSync('/etc/ssl/fullchain.pem'),
},
});
fastify.get('/', async () => ({ hello: 'https' }));
fastify.listen({ port: 443, host: '0.0.0.0' });
Koa
const Koa = require('koa');
const https = require('https');
const fs = require('fs');
const app = new Koa();
app.use(ctx => { ctx.body = 'Hello HTTPS'; });
https.createServer({
key: fs.readFileSync('/etc/ssl/privkey.pem'),
cert: fs.readFileSync('/etc/ssl/fullchain.pem'),
}, app.callback()).listen(443);
Next.js / Nuxt / autres serveurs de développement de frameworks
Les serveurs de développement des frameworks proposent généralement un flag --https pour le développement local. En production, utilisez toujours un reverse proxy — ces frameworks servent des fichiers statiques ou exécutent le SSR derrière Nginx, Caddy ou un load balancer cloud.
Modèle avec variables d’environnement
Ne codez pas les chemins de certificat en dur. Utilisez des variables d’environnement pour que le même code fonctionne en développement et en production :
const options = process.env.SSL_KEY ? {
key: fs.readFileSync(process.env.SSL_KEY),
cert: fs.readFileSync(process.env.SSL_CERT),
} : null;
if (options) {
https.createServer(options, app).listen(443);
console.log('HTTPS server on port 443');
} else {
app.listen(3000);
console.log('HTTP server on port 3000 (no SSL_KEY set)');
}
Développement avec des certificats auto-signés
Pour le développement local, générez un certificat auto-signé (pas pour la production) :
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 \
-keyout dev-key.pem -out dev-cert.pem -days 365 -nodes \
-subj "/CN=localhost"
const options = {
key: fs.readFileSync('./dev-key.pem'),
cert: fs.readFileSync('./dev-cert.pem'),
};
Votre navigateur affichera un avertissement (les certificats auto-signés ne sont pas approuvés) — cliquez pour continuer pendant le développement.
Rechargement des certificats à chaud
Pour recharger les certificats sans redémarrage (utile pour le renouvellement Let’s Encrypt) :
const tls = require('tls');
function loadCerts() {
return {
key: fs.readFileSync('/etc/ssl/privkey.pem'),
cert: fs.readFileSync('/etc/ssl/fullchain.pem'),
};
}
const server = https.createServer({
SNICallback: (hostname, cb) => {
const ctx = tls.createSecureContext(loadCerts());
cb(null, ctx);
},
}, app);
Cela relit les fichiers à chaque nouvelle connexion. Pour de meilleures performances, ajoutez un observateur de fichiers qui ne recharge que lorsque les fichiers changent.
Questions fréquemment posées
Dois-je gérer SSL dans Node.js ou utiliser un reverse proxy ?
En production : utilisez un reverse proxy. Pour le développement, les petits projets ou les services internes : le HTTPS direct dans Node.js convient. Le modèle reverse proxy est standard car il sépare les responsabilités et gère TLS plus efficacement.
Puis-je utiliser les certificats GetHTTPS avec Node.js ?
Oui. GetHTTPS produit des fichiers PEM standard (privkey.pem, fullchain.pem) que Node.js lit directement avec fs.readFileSync().
Comment gérer le renouvellement des certificats dans Node.js ?
Si vous utilisez un reverse proxy, remplacez simplement les fichiers et rechargez le proxy — Node.js n’a pas besoin de redémarrer. Si vous gérez TLS directement, utilisez l’approche SNICallback ci-dessus ou redémarrez le processus Node.js après avoir remplacé les fichiers de certificat.
Qu’en est-il du SSL localhost pour le développement ?
Utilisez un certificat auto-signé (montré ci-dessus) ou mkcert pour un certificat de développement approuvé localement. N’utilisez pas Let’s Encrypt pour localhost — il ne peut pas valider un domaine qui n’est pas accessible publiquement.
Puis-je utiliser les certificats GetHTTPS avec Deno ou Bun ?
Oui. Deno et Bun supportent tous deux TLS avec des fichiers PEM :
Deno :
Deno.serve({
port: 443,
cert: Deno.readTextFileSync("/etc/ssl/fullchain.pem"),
key: Deno.readTextFileSync("/etc/ssl/privkey.pem"),
}, (req) => new Response("Hello HTTPS"));
Bun :
Bun.serve({
port: 443,
tls: {
cert: Bun.file("/etc/ssl/fullchain.pem"),
key: Bun.file("/etc/ssl/privkey.pem"),
},
fetch(req) { return new Response("Hello HTTPS"); },
});
Les mêmes fichiers PEM de GetHTTPS fonctionnent avec tous les environnements d’exécution JavaScript.