/개발/Fixing "unable to get local issuer certificate" Errors in git, curl, pip, and npm
DevelopmentSSL인증서에러git 트러블슈팅

Fixing "unable to get local issuer certificate" Errors in git, curl, pip, and npm

Diagnose and fix "unable to get local issuer certificate" and "self signed certificate" SSL errors in git, curl, pip, and npm—with copy-paste commands by tool and OS. Covers Zscaler corporate proxies without setting sslVerify=false.

Fixing "unable to get local issuer certificate" Errors in git, curl, pip, and npm

Fix "unable to get local issuer certificate" in git, curl, pip, and npm in 5 minutes

If git clone worked yesterday and suddenly stopped

git clone that worked fine yesterday suddenly dies this morning with:

CODE
fatal: unable to access 'https://github.com/...': SSL certificate problem:
unable to get local issuer certificate

curl says this:

CODE
curl: (60) SSL certificate problem: self signed certificate in certificate chain

And pip throws a tantrum like this:

CODE
SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED]
certificate verify failed: unable to get local issuer certificate'))

The wording differs by tool, but the root cause is the same: the client could not verify the server certificate's issuer (CA) against its trust chain. Especially since 2026, SSL inspection (MITM) proxies like Zscaler and Netskope have become the corporate default, so this error is now a rite of passage for any developer who logs onto the office network.

This post goes in order: get the build running first → understand why → finish with the proper team-wide fix.

1. Start by telling the four root causes apart

Subtle differences in the error message tell you the cause.

CauseTypical error messageOne-line explanation
① Missing or expired CA bundleunable to get local issuer certificateClient has no root CA, or an outdated ca-bundle
② Corporate proxy (MITM)self signed certificate in certificate chainZscaler etc. intercept traffic and re-sign with their own root
③ Self-signed certificateself signed certificateInternal GitLab/Nexus issued its own cert
④ Wrong system clockcertificate has expired / not yet validPC clock is wrong, so validity checks fail

The key distinction: unable to get local issuer certificate means "I cannot find the issuer" (missing intermediate CA). self signed certificate in certificate chain means "the top of the chain is an untrusted self-signed cert" (MITM proxy or internal cert). If you see the latter, it is almost certainly a company proxy or an internal server.

2. Diagnostic commands: don't guess—inspect the certificate chain

First, see which certificates are actually being presented.

Bash
# Inspect the full certificate chain and issuer
openssl s_client -connect github.com:443 -showcerts </dev/null 2>/dev/null \
  | openssl x509 -noout -issuer -subject -dates

If issuer shows Zscaler Root CA or your company name → MITM proxy confirmed. If github.com is issued by your company, traffic is being re-signed in the middle.

Bash
# Peek at curl's verification steps
curl -v https://github.com 2>&1 | grep -E "issuer|subject|SSL certificate|verify"
Bash
# Compare system time vs. certificate validity (check cause ④)
date
openssl s_client -connect github.com:443 </dev/null 2>/dev/null \
  | openssl x509 -noout -dates

If notBefore is in the future, fix the PC clock first (sudo ntpdate / w32tm /resync).

3. Copy-paste fixes by tool (get unblocked first)

Assume the root certificate from IT (or extracted in step 4) is corp-ca.pem.

git

Bash
# Global
git config --global http.sslCAInfo /etc/ssl/certs/corp-ca.pem
# One repository only
git config http.https://gitlab.company.com.sslCAInfo /etc/ssl/certs/corp-ca.pem

curl

Bash
curl --cacert /etc/ssl/certs/corp-ca.pem https://github.com
# Apply globally via env var
export CURL_CA_BUNDLE=/etc/ssl/certs/corp-ca.pem

pippip.conf (Linux/macOS: ~/.pip/pip.conf, Windows: %APPDATA%\pip\pip.ini)

INI
[global]
cert = /etc/ssl/certs/corp-ca.pem
Bash
# One-off
pip install --cert /etc/ssl/certs/corp-ca.pem requests
# Global for requests-family libraries
export REQUESTS_CA_BUNDLE=/etc/ssl/certs/corp-ca.pem
export SSL_CERT_FILE=/etc/ssl/certs/corp-ca.pem

npm / node

Bash
npm config set cafile /etc/ssl/certs/corp-ca.pem
# Node runtime global (Yarn, fetch, etc.)
export NODE_EXTRA_CA_CERTS=/etc/ssl/certs/corp-ca.pem

Env vars (REQUESTS_CA_BUNDLE, NODE_EXTRA_CA_CERTS, SSL_CERT_FILE) are especially useful in CI/CD runners and Docker containers. Inject them once in the Dockerfile or runner environment instead of configuring every tool.

4. Permanently install the CA by OS (do it once, properly)

If you don't want to pass flags every time, register the cert in the system trust store.

OSCertificate locationApply command
Ubuntu/Debian/usr/local/share/ca-certificates/corp-ca.crtsudo update-ca-certificates
RHEL/CentOS/etc/pki/ca-trust/source/anchors/corp-ca.crtsudo update-ca-trust
macOSSystem keychainsudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain corp-ca.pem
WindowsTrusted Root storecertutil -addstore -f "ROOT" corp-ca.crt (or certmgr.msc)

Note: even after a system install, Python (certifi), Node, and Git for Windows often ship their own CA bundles, so you may still need the step-3 settings as well.

Extracting a corporate proxy root cert (Zscaler, etc.)

Asking IT is the most reliable path, but you can pull it yourself.

Bash
# Save the root cert the proxy re-signed with
openssl s_client -connect github.com:443 -showcerts </dev/null 2>/dev/null \
  | openssl x509 -outform PEM > corp-ca.pem

You can also click the padlock in the browser → View certificate → export the top of the chain (Zscaler Root CA) as Base64 (.pem). Register that file with the step 3 and 4 flow above.

5. Please do not use sslVerify=false

Turning verification off with the commands below because you're in a hurry throws the door wide open to MITM attacks.

⚠️ Danger — no temporary workarounds

Bash
git config --global http.sslVerify false      # Disables all HTTPS verification
pip install --trusted-host pypi.org ...        # No protection against tampered packages
npm config set strict-ssl false                # Exposed to supply-chain attacks

With verification off, you would never know if someone swapped the code in transit. Replace this with the proper approach above: register the correct CA.

A note from the field

After an SSL inspection proxy landed internally, I watched a team of dozens of developers each bypass it with sslVerify false. The actual fix was simple: put the company root cert in the internal package repo, and ship a one-liner CA install script in standard dotfiles and the base Docker image. SSL tickets almost disappeared after that. Having the team install it once is far cheaper than every individual turning verification off for five minutes.

Decision checklist

  1. openssl s_client ... -issuer → issuer is a company name? → MITM proxy; extract and register the root CA
  2. Issuer looks normal but you still get the error? → stale CA bundle; run update-ca-certificates / refresh certifi
  3. Hitting internal GitLab/Nexus? → self-signed cert; set sslCAInfo for that host only
  4. expired / not yet valid? → sync the system clock

FAQ

Q. I registered the CA and still get the error. A. The tool is not looking at the system store. For Python, use certifi (check the path with python -m certifi, then set REQUESTS_CA_BUNDLE). For Node, set NODE_EXTRA_CA_CERTS. For Git for Windows, set http.sslCAInfo separately. Also confirm the cert is PEM (Base64).

Q. SSL errors only happen inside Docker containers. A. Containers do not inherit the host CA store. In the Dockerfile, COPY corp-ca.crt /usr/local/share/ca-certificates/ then RUN update-ca-certificates, or inject NODE_EXTRA_CA_CERTS / REQUESTS_CA_BUNDLE as build args.

Q. It only fails on the corporate network; it works from home. A. Classic SSL inspection proxy (Zscaler, etc.). On the company network, traffic is re-signed, so you must trust the company root CA. Checking the issuer will show the company name.

Q. The error appears when I turn VPN on. A. The proxy is inserted over the VPN path and the certificate changes. Compare issuers with openssl s_client with VPN on and off, then register the proxy root CA on the system so both paths work.

확인 정보
✦ ✦ ✦
편집 검토 · Editorial Review

Nodelog는 모든 콘텐츠의 내용과 출처를 공개 전에 검토합니다. 환경(OS·버전)에 따라 결과가 달라질 수 있는 기술 정보는 공식 문서와 함께 확인하며, 검토 기준과 정정 원칙은 편집 정책에서 안내합니다. 오류를 발견하시면 이메일로 제보해 주세요 — 확인 후 신속히 정정합니다.

편집 책임 · Nodelog 기술 편집팀·발행 · ·업데이트 ·

Comments

Be the first to comment.