O Node.js possui suporte nativo a HTTPS através do módulo https. Você carrega seus arquivos de certificado e cria um servidor HTTPS. Este guia abrange Node.js puro, Express e a configuração recomendada para produção.
Servidor HTTPS básico
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 com 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');
});
Redirecionar HTTP para HTTPS
Execute ambos os servidores HTTP e HTTPS:
const http = require('http');
const https = require('https');
const fs = require('fs');
const express = require('express');
const app = express();
// ... suas rotas
const options = {
key: fs.readFileSync('/etc/ssl/privkey.pem'),
cert: fs.readFileSync('/etc/ssl/fullchain.pem'),
};
// Servidor HTTPS
https.createServer(options, app).listen(443);
// Redirecionamento HTTP
http.createServer((req, res) => {
res.writeHead(301, { Location: `https://${req.headers.host}${req.url}` });
res.end();
}).listen(80);
Recomendação para produção: proxy reverso
Para produção, não termine o TLS diretamente no Node.js. Use um proxy reverso (Nginx, Caddy ou um balanceador de carga) na frente:
Client ──HTTPS──→ Nginx (TLS termination) ──HTTP──→ Node.js (port 3000)
Razões:
- O Nginx processa TLS de forma mais eficiente (C vs JavaScript)
- A renovação do certificado não exige reiniciar o Node.js
- A porta 443 exige root — o Node.js não deve rodar como root
- Rate limiting, cache e compressão são gerenciados pelo proxy
- HTTP/2 possui suporte mais maduro no Nginx
O HTTPS direto no Node.js é adequado para desenvolvimento, serviços internos ou projetos pequenos.
Frameworks comuns
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 / outros servidores de desenvolvimento de frameworks
Os servidores de desenvolvimento de frameworks geralmente possuem uma flag --https para desenvolvimento local. Para produção, sempre use um proxy reverso — esses frameworks servem arquivos estáticos ou executam SSR atrás de Nginx, Caddy ou um balanceador de carga em nuvem.
Padrão com variáveis de ambiente
Não codifique os caminhos dos certificados diretamente no código. Use variáveis de ambiente para que o mesmo código funcione em desenvolvimento e produção:
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)');
}
Desenvolvimento com certificados autoassinados
Para desenvolvimento local, gere um certificado autoassinado (não usar em produção):
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'),
};
Seu navegador exibirá um aviso (certificados autoassinados não são confiáveis) — clique para continuar durante o desenvolvimento.
Recarregamento de certificados sem reiniciar
Para recarregar certificados sem reiniciar (útil para renovação do 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);
Isso relê os arquivos a cada nova conexão. Para melhor desempenho, adicione um observador de arquivos que recarrega apenas quando os arquivos mudam.
Perguntas frequentes
Devo gerenciar o SSL no Node.js ou usar um proxy reverso?
Para produção: use um proxy reverso. Para desenvolvimento, projetos pequenos ou serviços internos: HTTPS direto no Node.js funciona bem. O padrão de proxy reverso é o padrão da indústria porque separa responsabilidades e lida com TLS de forma mais eficiente.
Posso usar certificados do GetHTTPS com Node.js?
Sim. O GetHTTPS produz arquivos PEM padrão (privkey.pem, fullchain.pem) que o Node.js lê diretamente com fs.readFileSync().
Como lidar com a renovação de certificados no Node.js?
Se estiver usando um proxy reverso, basta substituir os arquivos e recarregar o proxy — o Node.js não precisa ser reiniciado. Se estiver gerenciando o TLS diretamente, use a abordagem SNICallback mostrada acima ou reinicie o processo Node.js após substituir os arquivos do certificado.
E quanto ao SSL localhost para desenvolvimento?
Use um certificado autoassinado (mostrado acima) ou mkcert para um certificado de desenvolvimento confiável localmente. Não use Let’s Encrypt para localhost — ele não pode validar um domínio que não é publicamente acessível.
Posso usar certificados do GetHTTPS com Deno ou Bun?
Sim. Tanto o Deno quanto o Bun suportam TLS com arquivos 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"); },
});
Os mesmos arquivos PEM do GetHTTPS funcionam em todos os runtimes JavaScript.