>_ josetilabs.com
← blog

21 out 2026 · ferramentas, linux, tls · 5 min

HTTPS no seu localhost com mkcert, sem aviso de certificado

mkcert cria uma autoridade certificadora na sua máquina, instala essa CA no trust store do sistema e do navegador, e assina um certificado para localhost, 127.0.0.1 e ::1. O navegador para de reclamar porque a cadeia fecha na CA em que ele já confia. Medido: com a CA passada em –cacert, o curl retorna HTTP 200 e ssl_verify_result 0 em 0,006 s; sem ela, falha com “unable to get local issuer certificate”.

O que mkcert faz

Certificado autoassinado assina a si mesmo. O navegador não tem motivo para confiar. mkcert separa em duas partes: a autoridade (rootCA.pem e rootCA-key.pem, criados uma vez) e o certificado folha, assinado por essa autoridade. O mkcert -install coloca a autoridade nos trust stores que o sistema e o navegador leem. Depois, qualquer certificado assinado por ela passa sem aviso.

O rootCA-key.pem é o segredo. Quem tiver esse arquivo pode emitir certificado válido para qualquer nome na sua máquina. Não copie para outro host, não commite, não compartilhe.

Instalação no Linux

Baixe o binário da página de releases (v1.4.4 em outubro de 2026). No Debian/Ubuntu, instale libnss3-tools antes, porque o mkcert só escreve no store do Firefox/Chrome se o certutil existir na hora do -install.

bash
sudo apt install libnss3-tools
# baixe mkcert-v*-linux-amd64 da página de releases
chmod +x mkcert
sudo mv mkcert /usr/local/bin/
mkcert -version

Gerar a CA e o certificado

bash
mkcert -install
mkcert -CAROOT
mkcert -cert-file ./localhost.pem -key-file ./localhost-key.pem localhost 127.0.0.1 ::1

O primeiro comando cria a CA e a instala. O segundo mostra onde ela mora (tipicamente ~/.local/share/mkcert). O terceiro gera localhost.pem e localhost-key.pem, válidos para localhost, 127.0.0.1 e ::1, expirando em 21 de janeiro de 2029.

Passe todos os nomes numa chamada só. Um certificado com vários SAN é mais fácil de gerenciar que cinco certificados.

Prova: servidor local com cadeado

Subi um servidor HTTPS na porta 8443 usando localhost.pem e localhost-key.pem. Com a CA em –cacert, o curl retorna HTTP 200 e ssl_verify_result 0 em 0,006 s. Sem a CA, falha com “unable to get local issuer certificate”. O navegador se comporta igual: com a CA instalada, sem aviso; sem ela, aviso.

Terminal mostrando mkcert -install, a emissão do certificado para localhost 127.0.0.1 e ::1, e o curl em https://localhost:8443 retornando http 200 com verify 0
Da CA instalada ao curl sem aviso, em uma máquina local.

Usar em Node, nginx e container

Node não lê o store do sistema por padrão. Aponte a CA com a variável de ambiente:

bash
NODE_EXTRA_CA_CERTS="$(mkcert -CAROOT)/rootCA.pem" node server.js

No nginx, use os arquivos gerados:

nginx
ssl_certificate /etc/nginx/certs/localhost.pem;
ssl_certificate_key /etc/nginx/certs/localhost-key.pem;

Num contêiner que precisa chamar o endpoint local, copie só o rootCA.pem e rode update-ca-certificates. Nunca copie a chave.

Quando não usar

mkcert é ferramenta de desenvolvimento, e a própria documentação é clara sobre isso. Para hostname público, use Let’s Encrypt. Para serviço interno com vários hosts e revogação real, use uma CA interna como step-ca. A linha é simples: mkcert para a máquina de um desenvolvedor; além disso, uma CA que alguém opera.

O artefato: script completo

bash
#!/usr/bin/env bash
set -euo pipefail

if ! command -v mkcert >/dev/null 2>&1; then
    echo "mkcert nao encontrado."
    echo "Linux: baixe o binario em https://github.com/FiloSottile/mkcert/releases"
    echo "Debian/Ubuntu: apt install libnss3-tools antes do mkcert -install"
    exit 0
fi

CAROOT="$(mkcert -CAROOT)"
echo "CA em: $CAROOT"

mkcert -install

mkcert -cert-file ./localhost.pem -key-file ./localhost-key.pem \
    localhost 127.0.0.1 ::1

echo "certificado: ./localhost.pem"
echo "chave: ./localhost-key.pem"
echo "use os dois no seu servidor local"

Como verificar

mkcert -CAROOT mostra o diretório da CA. openssl x509 -in localhost.pem -noout -subject -issuer -dates mostra emissor igual à CA local e datas válidas. curl --cacert "$(mkcert -CAROOT)/rootCA.pem" https://localhost:8443/ deve retornar HTTP 200 com ssl_verify_result 0.

Se der errado

Aviso de certificado no navegador. Causa: o mkcert -install não encontrou o store do navegador, porque o certutil não estava instalado. Correção: instale libnss3-tools (Debian/Ubuntu) ou nss-tools (RHEL) e rode mkcert -install de novo.

curl: (60) SSL certificate problem. Causa: a CA não foi passada. Correção: --cacert "$(mkcert -CAROOT)/rootCA.pem".

Certificado não cobre o nome. Causa: o nome usado no navegador não está na lista de SAN. Correção: regenere incluindo o nome exato, por exemplo mkcert ... app.localhost "*.localhost".

Porta 8443 em uso. Causa: outro processo. Correção: escolha outra porta no servidor ou mate o processo.

Tabela

Opção Confiança no navegador Quando usar
Certificado autoassinado não nunca em dev local se puder evitar
mkcert sim, na sua máquina desenvolvimento local
Let’s Encrypt sim, em todo lugar hostname público
step-ca sim, na rede interna vários hosts, revogação

FAQ

mkcert funciona no Windows e macOS? Sim. No Windows usa o store do sistema; no macOS, o Keychain. Firefox usa o próprio store NSS nos três.

Preciso rodar mkcert -install em cada projeto? Não. Uma CA por máquina. Gere quantos certificados quiser a partir dela.

O certificado expira? Sim, em cerca de 3 anos (o certificado medido expira em 21 de janeiro de 2029). Rode o comando de geração de novo.

Posso usar wildcard? Sim: mkcert "*.localhost". Útil para subdomínios locais.

É seguro usar em produção? Não. A CA local não tem revogação e a chave não deve sair da máquina.

Fontes

mkcert no GitHub, conferido em outubro de 2026, versão 1.4.4. O guia de mkcert para HTTPS local detalha trust stores por sistema operacional. Para o outro lado da conexão, o handshake TLS passo a passo. Para certificado público, Let’s Encrypt: 64 dias de certificado na borda.

Leia também

// Por e-mail

Os textos publicados aqui também vão por e-mail. O envio ainda não começou: quem deixar o endereço agora entra na primeira lista.

Guardo só o seu e-mail, a data e o registro desta autorização. Sem cookies, sem rastreador e nada compartilhado com terceiros. Detalhes na política de privacidade.