Todos os artigos
HTTPSmkcertlocal developmentlocalhost tunneling

HTTPS no localhost: mkcert vs túnel, comparados com honestidade

Duas ferramentas, um problema: seu servidor de desenvolvimento precisa ser alcançável por HTTPS. O mkcert te dá um certificado TLS confiável localmente para que https://localhost:3000 simplesmente funcione. Um túnel te dá uma URL HTTPS pública respaldada por um certificado real de uma CA real. Eles não são concorrentes — resolvem problemas diferentes —, mas as pessoas insistem em tratá-los como se fossem.

A resposta curta

  • Precisa de HTTPS só na sua própria máquina, para o seu próprio navegador? Use mkcert.
  • Precisa que um serviço externo (Stripe, GitHub, Auth0, um celular) alcance seu servidor de desenvolvimento? Use um túnel.
  • Ambos? Rode ambos. Eles não entram em conflito.

Esse é o artigo inteiro em três tópicos. O resto é só o porquê.

mkcert: certificados confiáveis localmente em 30 segundos

O mkcert instala uma autoridade certificadora local no armazenamento de confiança do seu sistema operacional e emite certificados a partir dela. Seu navegador vê o certificado como confiável porque a CA é confiável. Sem avisos de sua conexão não é particular, sem flags --ignore-certificate-errors, sem montar seus próprios certificados autoassinados.

# uma vez por máquina
mkcert -install

# uma vez por projeto
mkcert localhost 127.0.0.1

# agora você tem localhost.pem e localhost-key.pem

Conecte-os ao seu servidor de desenvolvimento (Vite, Next.js, Express, Django runserver_plus, todos suportam args de TLS) e você tem https://localhost:3000 com um certificado real.

O porém: só a sua máquina confia naquela CA. O navegador do seu colega vai avisar. Seu celular não vai confiar sem instalar manualmente a raiz da CA.

Túnel: HTTPS real, URL pública real

Um túnel localhost encaminha tráfego de uma URL HTTPS pública para a sua porta local. O certificado é emitido por uma CA real (Let's Encrypt ou similar) e confiado por cada navegador em cada dispositivo.

npx portpreview 3000

O túnel cuida da terminação TLS no gateway da nuvem. Seu servidor local pode ficar em HTTP puro — a URL pública é HTTPS, e essa é a superfície que cada serviço externo toca.

Lado a lado

NecessidademkcertTúnel
HTTPS no seu navegador localSimSim (via a URL pública)
Testes de service worker / cookie seguro no navegadorSimSim
Provedor externo consegue te alcançarNãoSim
Celular na sua mão consegue te alcançarNão (sem instalar a CA)Sim
Provedor OAuth aceita a URLÀs vezes (Google: sim; muitos: não)Sim
Stripe / GitHub / Twilio podem fazer webhookNãoSim
Tempo de configuração30 segundos por máquinaUm comando por sessão
Funciona offlineSimNão
Sobrevive ao modo aviãoSimNão

Onde as pessoas erram

Tentar usar mkcert para testes de webhook

O Stripe não consegue confiar na CA local da sua máquina. Não importa quão confiável o certificado pareça no seu navegador — o Stripe está em outra rede. Você precisa de um túnel para qualquer tráfego de entrada da internet pública.

Usar um túnel para HTTPS solo só de navegador

Se você só quer que service workers funcionem ou que um cookie seguro seja definido no seu próprio navegador, o mkcert é mais rápido e funciona offline. Não queime uma sessão de túnel pelo que um arquivo de certificado resolve.

Escolher uma ferramenta e forçar o outro caso de uso por ela

Rodar ambos é tranquilo. A maior parte da nossa configuração usa mkcert para o trabalho diário do lado do navegador e um túnel quando testamos webhooks ou callbacks OAuth. Eles coabitam no package.json sem conflito.

E o Caddy ou o nginx?

Sim, você pode rodar o Caddy com HTTPS automático na frente do seu servidor de desenvolvimento, e isso também funciona — é essencialmente "mkcert com passos extras e um proxy reverso". Para a maioria do desenvolvimento local, o mkcert é mais simples. Para roteamento mais elaborado com vários serviços locais, o Caddy compensa.

Nossa configuração de verdade

Um repo em que trabalhamos tem mkcert no script de dev para HTTPS do lado localhost, e um script npm tunnel à parte que roda portpreview quando alguém precisa de webhooks ou testes em mobile. A URL do túnel é passada por variável de ambiente para que as redirect URIs do OAuth sejam fáceis de trocar. Levou 20 minutos para montar e nunca mais pensamos em TLS local.

Para configuração de túnel específica de OAuth, veja como testar callbacks OAuth em local. Para compartilhar previews com colegas ou designers, compartilhar seu servidor de desenvolvimento local. Entre na lista de espera do PortPreview para o lado do túnel dessa configuração.

Perguntas frequentes

Devo usar mkcert ou um túnel para HTTPS local?
Ambos, para coisas diferentes. O mkcert dá ao seu próprio navegador um certificado confiável no localhost e funciona offline. Um túnel te dá uma URL HTTPS pública que serviços externos e outros dispositivos conseguem alcançar. Eles não entram em conflito — a maioria dos times usa ambos.
O mkcert dá conta de testes de webhook do Stripe ou GitHub?
Não. Os certificados do mkcert são confiáveis só na máquina que instalou a CA. Provedores de webhook externos não conseguem alcançar o localhost por mais confiável que o certificado seja no seu navegador local. Use um túnel para qualquer tráfego público de entrada.
O mkcert funciona para callbacks OAuth no localhost?
Alguns provedores (Google, certos níveis de dev do Auth0) aceitam localhost por HTTP ou HTTPS para desenvolvimento. Muitos não. O mkcert te dá HTTPS para os que aceitam; para os rígidos, é necessário um túnel com URL HTTPS pública.