SSL certificate problem: unable to get local issuer certificatesignifica que seu cliente não conseguiu construir uma cadeia de confiança do certificado do servidor para uma autoridade de certificação em que ele confia. A tentação é desabilitar a verificação. Não faça isso – isso remove totalmente a proteção contra interceptação. A solução real geralmente é simples.
📋 Table of Contents
- O que o erro significa
- Causa 1: O servidor não está enviando intermediários
- Causa 2: um pacote CA desatualizado ou ausente
- Causa 3: Interceptação TLS Corporativa
- Correções por ferramenta
- Causa 4: O certificado expirou
- Sequência Diagnóstica
- Por que não apenas desativar a verificação
- Perguntas Frequentes
- Conclusão
O que o erro significa
Quando um cliente se conecta por TLS, o servidor apresenta seu certificado mais quaisquer certificados intermediários. O cliente deve vincular essa cadeia a uma raiz confiável em seu armazenamento local de CA. O erro aparece quando um link está faltando – ou o servidor não enviou o intermediário ou seu armazenamento confiável local está ausente ou desatualizado.
Diagnosticar isso inspecionando a corrente.
openssl s_client -connect example.com:443 -showcerts </dev/null
# Look for the verification result at the end:
# Verify return code: 0 (ok)
# Verify return code: 20 (unable to get local issuer certificate)
# Verify return code: 21 (unable to verify the first certificate)
Código de retorno21 geralmente significa que o servidor é o culpado — ele não enviou seu certificado intermediário. Código de retorno20 geralmente significa que seu armazenamento confiável local é o problema.
Causa 1: O servidor não está enviando intermediários
Uma configuração incorreta comum do servidor. Os navegadores geralmente o ocultam porque armazenam em cache intermediários de visitas anteriores, de modo que o site “funciona no Chrome” enquanto o curl e o pipeline de CI falham.
# Count the certificates the server sends
openssl s_client -connect example.com:443 -showcerts </dev/null 2>/dev/null \
| grep -c "BEGIN CERTIFICATE"
# 1 means only the leaf — the intermediate is missing
Se você controla o servidor, conserte-o lá. O nginx precisa da folha e dos intermediários concatenados em um arquivo, nessa ordem.
# Correct order: leaf first, then intermediates
cat leaf.crt intermediate.crt > fullchain.crt
server {
# Use the full chain, not just the leaf certificate
ssl_certificate /etc/ssl/certs/fullchain.crt;
ssl_certificate_key /etc/ssl/private/privkey.key;
}
Certbotsfullchain.pem já contém a cadeia – apontando nginx paracert.pem em vez disso, é a causa mais frequente desse erro em sites Let’s Encrypt.
Causa 2: um pacote CA desatualizado ou ausente
Se a cadeia do servidor estiver completa, seu armazenamento confiável local estará obsoleto.
# Debian / Ubuntu
sudo apt update && sudo apt install --reinstall ca-certificates
sudo update-ca-certificates
# RHEL / Fedora
sudo dnf reinstall ca-certificates
sudo update-ca-trust
# Alpine (very common in Docker images)
apk add --no-cache ca-certificates
update-ca-certificates
# macOS
brew install ca-certificates
# or update curl, which bundles its own
brew install curl
Imagens mínimas do Docker são uma fonte frequente desse erro porque são fornecidas sem nenhum pacote CA. Adicionandoca-certificates à imagem geralmente resolve em uma linha.
Causa 3: Interceptação TLS Corporativa
Muitas redes corporativas interceptam o TLS, apresentando seu próprio certificado assinado por uma CA interna. Os navegadores funcionam porque o CA é instalado no nível do sistema operacional por meio do gerenciamento de dispositivos; ferramentas de linha de comando com seus próprios armazenamentos confiáveis, não.
A solução é adicionar a CA raiz corporativa ao armazenamento confiável relevante – não desabilitar a verificação.
# Capture the certificate the proxy is presenting
openssl s_client -showcerts -connect example.com:443 </dev/null \
| openssl x509 -outform PEM > corp-ca.crt
# Inspect it to confirm what it is
openssl x509 -in corp-ca.crt -noout -subject -issuer -dates
# Install system-wide (Debian/Ubuntu)
sudo cp corp-ca.crt /usr/local/share/ca-certificates/corp-ca.crt
sudo update-ca-certificates
Peça ao seu departamento de TI o arquivo CA raiz oficial em vez de extraí-lo você mesmo sempre que possível – extrair de uma conexão ativa pressupõe que a conexão ainda não esteja comprometida.
Correções por ferramenta
enrolar
# Point at a specific bundle
curl --cacert /path/to/ca-bundle.crt https://example.com
# Or set it for the session
export CURL_CA_BUNDLE=/path/to/ca-bundle.crt
Git
# Correct fix: point Git at a valid bundle
git config --global http.sslCAInfo /path/to/ca-bundle.crt
# Scope it to one host if only that host is affected
git config --global http."https://internal.company.com/".sslCAInfo /path/to/corp-ca.crt
git config --global http.sslVerify false aparece em todos os resultados da pesquisa para esse erro. Ele desativa permanentemente a verificação de certificado para cada host do qual você clonou. Não use isso.
Node.js
# Add a CA to Node's trust store for this process
export NODE_EXTRA_CA_CERTS=/path/to/corp-ca.crt
node app.js
// Or per-request, which is more precise
import https from 'node:https';
import fs from 'node:fs';
const agent = new https.Agent({
ca: fs.readFileSync('/path/to/corp-ca.crt'),
});
await fetch('https://internal.example.com', { agent });
NODE_TLS_REJECT_UNAUTHORIZED=0 desativa a verificação em todo o processo e o Node imprime um aviso dizendo exatamente isso. É aceitável em um teste local descartável e em nenhum outro lugar.
Píton
import certifi, requests
# Use certifi's bundle explicitly
requests.get('https://example.com', verify=certifi.where())
# Or a corporate CA
requests.get('https://internal.example.com', verify='/path/to/corp-ca.crt')
# Environment variables respected by requests and urllib3
export REQUESTS_CA_BUNDLE=/path/to/ca-bundle.crt
export SSL_CERT_FILE=/path/to/ca-bundle.crt
# Keep certifi current
pip install --upgrade certifi
Docker
FROM node:22-alpine
# Alpine ships without a CA bundle
RUN apk add --no-cache ca-certificates
# Add a corporate CA if you are behind interception
COPY corp-ca.crt /usr/local/share/ca-certificates/
RUN update-ca-certificates
ENV NODE_EXTRA_CA_CERTS=/etc/ssl/certs/ca-certificates.crt
Causa 4: O certificado expirou
Verifique antes de assumir um problema de armazenamento confiável.
echo | openssl s_client -connect example.com:443 2>/dev/null \
| openssl x509 -noout -dates
# notBefore=...
# notAfter=...
Verifique também o relógio do cliente. Uma máquina com uma data muito errada rejeita certificados válidos como ainda não válidos ou expirados, e isso detecta contêineres e máquinas virtuais que foram suspensas.
date
timedatectl status # Linux
Sequência Diagnóstica
openssl s_client -connect host:443 -showcerts— leia o código de retorno de verificação- Conte os certificados enviados. Um significa um intermediário ausente no servidor.
- Verifique as datas de validade e o relógio do sistema local.
- Compare com outra máquina ou rede – se funcionar lá, o problema é local.
- Verifique se o emissor é sua CA corporativa, o que indica interceptação.
- Atualização
ca-certificatese qualquer pacote específico de idioma.
Por que não apenas desativar a verificação
Porque a verificação do certificado é todo o mecanismo que impede que alguém na rede se faça passar pelo servidor com o qual você pensa que está conversando. Desativá-lo significa que qualquer intermediário pode ler e modificar o tráfego – incluindo credenciais, tokens e os pacotes que você está baixando.
O risco realista não é teórico. Um pipeline de CI com verificação desabilitada instalará com prazer um pacote de um registro personificado. A correção leva minutos; a consequência de ignorá-lo pode ser uma construção comprometida.
Perguntas Frequentes
P: Por que funciona no meu navegador, mas não no curl?
R: Os navegadores armazenam em cache certificados intermediários de conexões anteriores e podem buscar automaticamente os ausentes. curl não faz nada disso, então expõe um problema de cadeia do lado do servidor que os navegadores escondem.
P: Qual é a diferença entre o erro 20 e o erro 21?
R: 21 significa que o cliente não pôde verificar o primeiro certificado, normalmente porque os intermediários não foram enviados. 20 significa que o emissor não foi encontrado em seu armazenamento confiável local.
P: Onde está o pacote CA no meu sistema?
R: Geralmente/etc/ssl/certs/ca-certificates.crt no Debian e Ubuntu,/etc/pki/tls/certs/ca-bundle.crt no RHEL. Em Python,python -m certifi imprime o caminho que o certificado usa.
P: É seguro desabilitar a verificação apenas para desenvolvimento local?
R: Para um servidor local com um certificado autoassinado, adicione esse certificado ao seu armazenamento confiável — isso leva o mesmo tempo e não cria um hábito que o acompanha até a configuração de produção.
P: Meu CI funciona, mas a produção falha. Por que?
R: Quase sempre há diferença na imagem base. Imagens Slim e Alpine frequentemente omitemca-certificates inteiramente.
Conclusão
Este erro significa que a cadeia de confiança foi quebrada e existem apenas algumas causas:o servidor não está enviando seus certificados intermediários, seu pacote de CA local está ausente ou desatualizado, um proxy corporativo está interceptando o TLS com sua própria CA ou um certificado expirou. Diagnosticar comopenssl s_client e o código de retorno de verificação e, em seguida, corrija a causa real – instale a CA, atualizeca-certificatesou atenda a cadeia completa. Nunca desative a verificação fora de um teste local descartável, pois isso remove a proteção que o erro existe para fornecer.
🔗 Share this article
✍️ Leave a Comment