mediumIntermediateSymptom-first#tls#chain#intermediate#ca

TLS certificate chain incomplete — intermediate missing

openssl s_client shows 'unable to get local issuer certificate'

Likely source:configurationconnectivity

Focused incident mode — strips away everything but this runbook.

Symptoms

  • openssl s_client shows 'unable to get local issuer certificate'
  • curl fails with 'unable to verify the first certificate'
  • Browser trusts some clients but not others

Evidence to grab

Collect these artifacts before you change anything — they prove (or rule out) each cause.

  • Chain presented by the server

    echo | openssl s_client -connect <HOST>:443 2>/dev/null | openssl crl2pkcs7 -nocrl -certfile /dev/stdin | openssl pkcs7 -print_certs -noout

Diagnostic flow

Run the steps in order, marking each claim confirmed or refuted. The evidence you gather feeds the ranked causes below.

Guided decision tree is ready.

Steps with commands, expected output, and pass/fail branches.

Ranked root causes

Evidence checklist

  • TCP capture or s_client shows a single cert in the chain
  • Clients with a full CA cache succeed; cold-cache clients fail

Confirm before fixing

echo | openssl s_client -connect <HOST>:443 2>/dev/null | grep 'BEGIN CERTIFICATE'
READ

Leaf-only presentation

Fix

cat leaf.crt intermediate.crt root.crt > chained.crt && install -m 0644 chained.crt /etc/nginx/ssl/<HOST>.crt
CHANGE

Concatenate leaf + intermediates into the served bundle

Resolution runbook

Apply from top to bottom after the cause is confirmed. Review every command before running it — risk tags are shown on each.

1
echo | openssl s_client -connect <HOST>:443 2>/dev/null | openssl x509 -noout -issuer -subject
READ

Inspect leaf issuer/subject

2
openssl verify -CAfile <ROOT> -untrusted <INTERMEDIATE> <LEAF>
READ

Rebuild a correct chain file and concatenate leaf + intermediates

Prevention

  • Automate renewal to output a combined chain bundle (leaf + intermediates).
  • Include chain validation in deploy CI (openssl verify).
  • Use ACME/cert-manager outputs that already include the chain.

Commands marked READ CHANGE DESTRUCTIVE — never run DESTRUCTIVE commands against production data you cannot restore. Copy → verify → execute.