This is one of the most confusing certificate faults because it works for you. Desktop browsers cache intermediate certificates from other sites and quietly fill the gap; a phone that has never seen that intermediate, and every command-line client, cannot.
The symptom
- Fine on your laptop, untrusted on a phone.
- curl says unable to get local issuer certificate.
- A payment gateway or webhook cannot connect while browsers are happy.
Confirm it
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com < /dev/null 2>/dev/null \
| grep -E '^ *[0-9]+ s:|Verify return code'
You want at least two certificates listed - yours and the intermediate - and Verify return code: 0 (ok). One certificate and a verify error is exactly this fault.
The cause is one filename
Serving cert.pem instead of fullchain.pem. cert.pem is your certificate alone; fullchain.pem is your certificate followed by the intermediate. It is one word in the configuration and it is almost always the whole problem.
# nginx - correct
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# apache / litespeed
SSLCertificateFile /etc/letsencrypt/live/example.com/cert.pem
SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem
Reload and check again
sudo nginx -t && sudo systemctl reload nginx
curl -sS -o /dev/null -w '%{http_code}\
' https://yourdomain.com
Test from something that has no cache
curl on a machine that has never visited the site, or a phone on mobile data with the site cleared. Your own browser is the one client that cannot tell you the answer - see works on wifi but not on mobile data.