APIs web modernas (service workers, geolocalização, clipboard, câmera) exigem HTTPS — mesmo durante o desenvolvimento. Este guia cobre como obter HTTPS confiável no localhost sem avisos do navegador.
Por que você não pode usar Let’s Encrypt para localhost
O Let’s Encrypt válida a propriedade do domínio verificando um arquivo no seu servidor ou um registro DNS. localhost não é um domínio real — ele resolve para 127.0.0.1 apenas na sua máquina. Ninguém pode verificar que você “possui” localhost, então nenhuma CA pública emitirá um certificado para ele.
Suas opções para HTTPS no localhost:
- mkcert — cria certificados confiáveis localmente (recomendado)
- Certificado autoassinado — funciona mas mostra avisos no navegador
- Serviço de tunelamento — ngrok, Cloudflare Tunnel (domínio real, certificado real)
Opção 1: mkcert (recomendado)
O mkcert cria uma Autoridade Certificadora local na sua máquina, a adiciona ao armazenamento de confiança do sistema e emite certificados assinados por essa CA. Os navegadores confiam nesses certificados sem avisos.
Instalar mkcert
# macOS
brew install mkcert
# Linux (requer libnss3-tools para Firefox)
sudo apt install libnss3-tools
brew install mkcert # ou baixe dos releases no GitHub
# Windows
choco install mkcert
# ou: scoop install mkcert
Configurar a CA local
mkcert -install
# Saída: Created a new local CA
# A CA local agora está instalada no armazenamento de confiança do sistema
Isso adiciona um certificado raiz aos armazenamentos de confiança do seu sistema e navegador. Faça isso uma vez — funciona para todos os certificados futuros.
Gerar certificados
# Para localhost
mkcert localhost 127.0.0.1 ::1
# Para um domínio local personalizado
mkcert myapp.test "*.myapp.test" localhost 127.0.0.1
# Saída:
# Created a new certificate valid for the following names:
# - "localhost"
# - "127.0.0.1"
# - "::1"
# The certificate is at "./localhost+2.pem" and the key at "./localhost+2-key.pem"
Usar com seu servidor de desenvolvimento
Node.js/Express:
const https = require('https');
const fs = require('fs');
const app = require('./app');
https.createServer({
key: fs.readFileSync('./localhost+2-key.pem'),
cert: fs.readFileSync('./localhost+2.pem'),
}, app).listen(3000);
Nginx (local):
server {
listen 443 ssl;
server_name localhost;
ssl_certificate /path/to/localhost+2.pem;
ssl_certificate_key /path/to/localhost+2-key.pem;
# ...
}
Vite / webpack dev server:
// vite.config.js
import fs from 'fs';
export default {
server: {
https: {
key: fs.readFileSync('./localhost+2-key.pem'),
cert: fs.readFileSync('./localhost+2.pem'),
},
},
};
Aviso de segurança
Nunca compartilhe a chave da CA raiz do mkcert (rootCA-key.pem em mkcert -CAROOT). Qualquer pessoa que a possua pode criar certificados confiáveis para qualquer domínio na sua máquina — essencialmente uma capacidade de man-in-the-middle local.
O mkcert é apenas para desenvolvimento. Para produção, use Let’s Encrypt.
Opção 2: Certificado autoassinado
Se você não pode instalar o mkcert, gere um certificado autoassinado com OpenSSL:
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 \
-keyout localhost-key.pem -out localhost-cert.pem \
-days 365 -nodes -subj "/CN=localhost" \
-addext "subjectAltName=DNS:localhost,IP:127.0.0.1"
Desvantagem: Os navegadores mostram um aviso de segurança porque certificados autoassinados não são confiáveis por nenhuma CA. Você precisará clicar no aviso cada vez (ou adicionar uma exceção).
Opção 3: Tunelamento (domínio real + certificado real)
Use um serviço de tunelamento para expor seu servidor local com um domínio e certificado reais:
# ngrok
ngrok http 3000
# Fornece: https://abc123.ngrok.io
# Cloudflare Tunnel
cloudflared tunnel --url http://localhost:3000
# Fornece: https://random-name.trycloudflare.com
Quando faz sentido: testar webhooks, compartilhar com um colega, testar callbacks OAuth que exigem HTTPS.
mkcert vs autoassinado vs tunelamento
| mkcert | Autoassinado | Tunelamento | |
|---|---|---|---|
| Avisos do navegador | Nenhum | Sim (cada sessão) | Nenhum |
| Esforço de configuração | Baixo (uma instalação) | Baixo (um comando) | Baixo |
| Funciona offline | ✅ | ✅ | ❌ |
| Desempenho | Velocidade local | Velocidade local | Latência de rede |
| Domínios personalizados | ✅ (*.test, etc.) | ✅ | Atribuído pelo provedor |
| Melhor para | Desenvolvimento diário | Uma necessidade rápida | Webhooks, compartilhamento |
Perguntas frequentes
Posso usar o mesmo certificado mkcert em toda a equipe?
Não compartilhe a chave da CA raiz. Cada desenvolvedor deve executar mkcert -install na própria máquina para criar sua própria CA local. Você pode compartilhar os certificados gerados (os arquivos .pem), mas cada pessoa precisa da CA instalada para confiar neles.
O mkcert funciona com Docker?
Sim. Monte os arquivos de certificado no container e referencie-os na configuração do servidor. O container em si não precisa do mkcert instalado — apenas os arquivos .pem. Sua máquina host (onde o navegador roda) precisa da CA do mkcert instalada.
Qual domínio local devo usar?
Use .test (ex.: myapp.test) — ele é reservado pelo IETF para testes e nunca conflitará com um domínio real. Evite .dev (pertence ao Google) e .local (usado por mDNS). Adicione uma entrada em /etc/hosts para apontar seu domínio .test para 127.0.0.1.
Como faço a troca de HTTPS em localhost para HTTPS em produção?
São completamente separados. Seu certificado localhost (mkcert/autoassinado) fica na sua máquina de desenvolvimento. Para produção, obtenha um certificado real do Let’s Encrypt via GetHTTPS. Seu código deve ler os caminhos dos certificados de variáveis de ambiente para que a troca seja apenas uma mudança de configuração.