Kort svar

"unable to get local issuer certificate" betyder at klienten ikke kunne bygge en komplet tillidskæde fra serverens certifikat op til en root den stoler på. Den manglende brik er næsten altid intermediate-certifikatet, som serveren har glemt at sende. Løsningen er at installere fullchain-certifikatet — leaf + intermediate(s) — på serveren.

Hvorfor virker det i browseren men ikke i curl?

Browsere er eftergivende: de cacher intermediates fra tidligere besøg, og mange kan endda hente en manglende intermediate via AIA-feltet i certifikatet. curl, OpenSSL, Java og de fleste server-biblioteker gør ikke det — de kræver at serveren selv sender hele kæden. Derfor opdages fejlen ofte først når en backend-integration går i luften, ikke i QA i browseren.

Bekræft det: hvor mange certifikater sender serveren?

openssl s_client -connect example.com:443 -servername example.com -showcerts 2>/dev/null \
  | grep -c "BEGIN CERTIFICATE"

Får du 1, sender serveren kun leaf-certifikatet — kæden mangler. Får du 2 eller mere, sendes intermediate(s) med. Du kan også se det direkte i Verify return code: — kode 20 er præcis denne fejl.

Sådan retter du det på serveren

Installer det certifikat din CA kalder fullchain.pem eller chain-bundlet — ikke kun cert.pem. Eksempler:

# nginx — brug fullchain, ikke kun leaf
ssl_certificate     /etc/ssl/example.com/fullchain.pem;
ssl_certificate_key /etc/ssl/example.com/privkey.pem;

# Apache — moderne versioner kæder automatisk hvis filen indeholder kæden
SSLCertificateFile    /etc/ssl/example.com/fullchain.pem
SSLCertificateKeyFile /etc/ssl/example.com/privkey.pem

Med Let's Encrypt/certbot er fullchain.pem allerede den rigtige fil — fejlen opstår typisk når nogen manuelt har peget på cert.pem i stedet. Reload tjenesten bagefter og verificér med tællingen ovenfor.

Den anden årsag: en manglende root i klientens trust store

Sjældnere, men reelt: hvis serveren sender hele kæden korrekt, men klienten ikke har den pågældende root i sin trust store, ses samme fejl. Det rammer typisk ældre systemer der mangler opdaterede CA-bundles, eller interne CA'er der ikke er distribueret til klienterne. Se også "virker i browser, ikke i Java/.NET".

Sådan fanger du det før kunderne gør

En manglende kæde er usynlig i en browser-baseret test — det er netop derfor den slipper igennem til produktion. CertControl validerer hele kæden udefra på hvert endpoint, ikke bare leaf-certifikatet, og markerer enhver server der kun sender et delvist chain. Så opdager du det ved næste scan, ikke når en partners integration fejler.

Ofte stillede spørgsmål

Hvad er forskellen på cert.pem og fullchain.pem?

cert.pem indeholder kun dit eget (leaf) certifikat. fullchain.pem indeholder leaf + de nødvendige intermediates. Brug altid fullchain på serveren, ellers risikerer du denne fejl.

Hvorfor henter klienten ikke bare den manglende intermediate selv?

Nogle browsere kan via AIA-feltet, men det er ikke garanteret og er langsomt. curl, Java og de fleste server-biblioteker gør det ikke. Best practice er at serveren altid sender hele kæden.

Skal serveren også sende root-certifikatet?

Nej. Root'en skal være i klientens trust store, ikke sendes af serveren. At sende root'en med er unødvendigt (men ikke skadeligt). Det er intermediate'en der skal med.

Verify return code 20 — hvad betyder det?

Det er OpenSSL's kode for netop "unable to get local issuer certificate": kæden kunne ikke bygges færdig op til en betroet root.