自签名证书错误ERR_CERT_COMMON_NAME_INVALID
小程序在电脑上可以正常获取数据,但是发布后无法正常连接,并且报错ERR_CERT_COMMON_NAME_INVALID
服务器配置ssl证书后,检测显示缺少证书链,导致微信小程序无法连接
域名通过了ipc备案, 宝塔服务器上的ssl证书也配置正确,浏览器左上角显示连接是安全的,看上去证书有效。
但是小程序依旧无法访问服务端,无法获取数据。打开调试模式报错NET::ERR_CERT_AUTHORITY_INVALID
err cert authority invalid 这意味着浏览器认为该网站的SSL证书不是由受信任的证书颁发机构(CA)签发的。这可能是由于多种原因造成的,包括证书过期、自签名证书、中间证书缺失等
因为使用了宝塔自己代码的续签,导致了中间证书缺少 无法正常访问 : 缺少中级证书Intermediate,请安装中级证书否则证书在部分浏览器中不受信任
原因是证书链不完整 需要对中间证书进行补全 或者重新手动续签证书
当浏览器不信任 SSL 证书时,就会发生 NET::ERR_CERT_AUTHORITY_INVALID 错误。
下面这个网址可以检测ssl证书是否正常
https://www.myssl.cn/tools/check-server-cert.html
宝塔面板接口返回差异:手动续签时,宝塔面板会自动拼接「叶证书(服务器证书)+ 中级证书(Intermediate)」形成完整的证书链并返回;而通过/acme?action=renew_cert接口直接请求时,返回的.cert字段仅包含叶证书,未自动携带中级证书链,这是接口的默认返回行为(并非脚本逻辑错误,而是接口返回数据不完整)。
测试xyz
缺少中间证书 分析代码中的 中间证书 是怎么获取的intermediate.pem
openssl x509 -in in.pem -noout -dates
检查中间证书过期时间
中间证书定义
采用 Here Document 格式保留
INTERMEDIATE_CERT的 PEM 格式完整性,避免特殊字符转义问题示例为 Let's Encrypt R3 中间证书(长期有效,如需更新可从Let's Encrypt 官方下载)
若使用其他 CA 机构(如 ZeroSSL),需替换为对应中间证书
拼接
域名证书 + 中间证书,形成完整的二级证书链覆盖写入原
fullchain.pem,确保宝塔面板读取的是完整证书链
当 ACME 客户端完成域名验证后,会调用 send_csr 方法提交 CSR(证书签名请求)。ACME 服务器处理后会返回一个 证书 URL。
随后,客户端通过 download_cert(self, index) 方法从该 URL 下载证书数据
root_cert.csr:文件名有误导性,实际内容是 中间证书(Intermediate Certificate)。
cert.csr:仅包含 域名证书(Leaf Certificate)
fullchain.pem:这是标准的 完整证书链(Leaf + Intermediate),供 Nginx/Apache 使用。
ACME 客户端不生成中间证书,而是从 ACME 服务器返回的响应中提取。中间证书是由 Let's Encrypt 在签发证书时自动附加在其响应体中的,客户端只需正确解析和保存即可
t1辅助域名续签 检查成功后,再给主域名 ftp和re去续签
letsencrypt_v2 在代码中是在什么时候更新这个文件的的
订单相关更新:创建 / 修改 / 删除 / 续签 SSL 订单时
这是最频繁的更新场景,涉及create_order()、save_order()、remove_order()、renew_cert()等方法:
创建订单:create_order()创建订单后,调用save_order(),将订单标识、域名、验证类型、过期时间等写入orders字段,save_config()落地文件。
更新订单验证信息:get_auths()方法获取域名验证信息(http-01/dns-01)后,将验证令牌、挑战地址等存入对应订单,save_config()更新。
删除订单:remove_order()删除指定订单,revoke_order()吊销证书后删除订单,均会调用save_config()更新orders字段。
续签订单:renew_cert()、renew_cert_to()续签证书时,更新订单的renew_time、cert_timeout等字段,save_config()落地最新续签信息。
5. 证书相关更新:下载 / 保存 SSL 证书时
涉及send_csr()、download_cert()、save_cert()方法:
发送 CSR 后:send_csr()获取证书下载地址,将certificate_url写入对应订单,save_config()更新。
下载证书后:download_cert()下载证书并解析到期时间,save_cert()保存证书文件后,将cert_timeout(到期时间)、save_path(证书存储路径)写入订单,save_config()更新letsencrypt_v2.json。
6. 其他零散更新:计划任务 / 重试次数等
计划任务配置:set_crond()方法创建证书续签计划任务后,若有配置变更,会调用save_config()更新。
续签重试记录:renew_cert_to()若续签失败,会记录retry_count(重试次数)、next_retry_time(下次重试时间),调用save_config()落地到对应订单。
三、核心更新入口:save_config()方法(所有更新的统一落地)
无论上述哪种场景,最终都通过save_config()方法完成letsencrypt_v2.json的写入,其核心逻辑:
以w+模式打开letsencrypt_v2.json(不存在则创建,存在则覆盖原有内容)。
加文件排他锁(fcntl.LOCK_EX),避免多进程同时写入造成文件损坏。
将内存中的_config字典序列化为 JSON 字符串,写入文件。
释放文件锁(fcntl.LOCK_UN),关闭文件句柄。
需要在现有脚本中加入宝塔 letsencrypt_v2.json 配置保存(saveconfig 核心逻辑),确保证书续签后配置信息同步更新,避免后续续签 / 管理出现配置不一致问题
删除 `letsencrypt_v2.json` 后再续签,查看 文件是否更新