CURLOPT_SSL_VERIFYHOST提示Let's Encrypt证书过期问题排查
解决cURL设置CURLOPT_SSL_VERIFYHOST=2时Let's Encrypt证书域名路径请求报错问题
问题概述
当设置CURLOPT_SSL_VERIFYHOST=2后,使用cURL请求带路径/参数的Let's Encrypt签发证书的域名时,会返回错误:SSL certificate problem: certificate has expired。但直接请求根域名无异常,且证书链检测显示有效;同时使用CloudFlare或亚马逊签发证书的域名无此问题。
核心原因
这是由于系统中旧的Let's Encrypt根证书(DST Root CA X3)过期后,部分版本的cURL在处理带路径的请求时,证书链验证逻辑出现偏差,错误优先选择了过期的根证书进行验证;而根域名请求的证书链处理逻辑不同,避开了该问题。
可行解决方案
- 更新系统根证书库:确保系统根证书为最新状态,移除过期的DST Root CA X3,保留有效的ISRG Root X1证书。
- Debian/Ubuntu系统执行:
sudo apt update && sudo apt install ca-certificates - RHEL/CentOS系统执行:
sudo yum update ca-certificates
- Debian/Ubuntu系统执行:
- 手动指定CA证书文件:通过
CURLOPT_CAINFO参数指定包含ISRG Root X1的CA证书路径,强制cURL使用有效证书链验证:curl_setopt($ch, CURLOPT_CAINFO, '/etc/ssl/certs/ca-certificates.crt'); // 替换为系统实际CA证书路径 - 升级cURL版本:将cURL升级到7.79.0及以上版本,新版本修复了证书链选择逻辑,会优先使用有效的ISRG Root X1证书。
测试代码复现
<?php $testUrls = [ 'https://letsencrypt.org', // 根域名请求正常 'https://letsencrypt.org/docs/', // 带路径请求报错 'https://cloudflare.com', // CloudFlare证书域名正常 'https://aws.amazon.com' // 亚马逊证书域名正常 ]; foreach ($testUrls as $url) { $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); $response = curl_exec($ch); if (curl_errno($ch)) { echo "URL: $url\nError: " . curl_error($ch) . "\n\n"; } else { echo "URL: $url\nRequest succeeded\n\n"; } curl_close($ch); } ?>
内容的提问来源于stack exchange,提问作者user3934058
相关产品推荐
相关产品推荐

