宝塔用户_coyxvt 发表于 2026-8-8 18:31:22

标题:Docker网站申请SSL覆盖原证书订单并报TypeError

一、环境信息

系统:OpenCloudOS 9.2 x86_64
Python:3.7.16
宝塔Linux面板:11.8.1
网站类型:Docker项目管理中的反向代理网站
Web服务:Nginx
证书申请:免费证书,HTTP文件验证
测试域名:actionlog.ccnln.com

二、问题现象

1. 在“Docker项目管理 -> 网站 -> SSL -> 免费证书”中申请证书时,面板弹出:

TypeError: list indices must be integers or slices, not str

2. 申请失败后,原本 letsencrypt_v2.json 中已存在的其他有效证书订单会丢失,免费证书列表只剩下本次失败的 pending 订单。

3. 某些申请流程中,日志显示文件验证目录被错误设置为:

["actionlog.ccnln.com"]/.well-known/acme-challenge

而不是 Docker 网站的真实运行目录。

三、复现步骤

1. 在 Docker 项目管理中创建反向代理网站并绑定域名。
2. 使面板的免费证书列表中已存在其他有效订单。
3. 进入该 Docker 网站的 SSL 页面。
4. 选择 HTTP 文件验证并申请免费证书。
5. 面板在创建 ACME 订单、获取验证信息阶段报 TypeError。
6. 重新打开免费证书列表,可能发现原有订单被新的 pending 订单覆盖。

四、关键报错堆栈

Traceback (most recent call last):
File "/www/server/panel/mod/project/docker/sites/sslManage.py", line 2091, in apply_cert
    self.get_auths(index)
File "/www/server/panel/mod/project/docker/sites/sslManage.py", line 1376, in write_ngin_authx_file
    site_name, project_type = self.get_site_name_by_domains(...)
File "/www/server/panel/mod/project/docker/sites/sslManage.py", line 1312, in get_site_name_by_domains
    siteName, project_type = site_data["name"], site_data["project_type"]
TypeError: list indices must be integers or slices, not str

更新/修复面板后,申请入口改为调用全局 ACME 模块,仍可复现:

Traceback (most recent call last):
File "/www/server/panel/class/acme_v2.py", line 2569, in apply_cert
    self.get_auths(index)
File "/www/server/panel/class/acme_v2.py", line 955, in write_ngin_authx_file
    site_name, project_type = self.get_site_name_by_domains(...)
File "/www/server/panel/class/acme_v2.py", line 1543, in get_site_name_by_domains
    siteName, project_type = site_data["name"], site_data["project_type"]
TypeError: list indices must be integers or slices, not str

五、定位到的原因

1. Docker ACME 初始化未读取已有订单

/www/server/panel/mod/project/docker/sites/sslManage.py 中的 ACME 对象初始化时没有先调用 read_config()。新建订单时会从空的 class-level _config 字典开始,随后 save_ssl_config() 直接覆盖:

/www/server/panel/config/letsencrypt_v2.json

导致原有证书订单丢失。

2. Docker SSL 错误查询普通网站表

Docker 网站的域名和站点记录存放在 docker_domain 和 docker_sites 表。但 get_site_name_by_domains() 查询的是普通网站的 domain 和 sites 表。

本机普通网站表中刚好存在历史残留域名记录:

domain.name = actionlog.ccnln.com
domain.pid = 12

但 sites.id=12 已不存在。find() 因此返回空列表,后续代码却直接使用 site_data["name"],从而触发 TypeError。

3. 全局 ACME 模块没有 Docker 站点回退查询

Docker apply_cert_api() 实际会调用 /www/server/panel/class/acme_v2.py。全局 ACME 的 get_site_name_by_domains() 同样只查询普通网站表,没有在查询失败时回退到 docker_domain/docker_sites。

4. Docker HTTP 验证路径参数处理错误

前端传入的 auth_to 可能是域名 JSON 字符串,例如 ["actionlog.ccnln.com"]。后端未将它转换为 Docker 网站的实际运行目录,导致 ACME Challenge 文件写入错误路径。

六、建议修复方案

1. Docker ACME 对象初始化时创建实例级 _config,并立即调用 read_config(),保证新订单与旧订单合并,不覆盖整个文件。

2. Docker SSL 模块的 get_site_name_by_domains() 应查询 docker_domain 和 docker_sites,而不是普通 domain/sites。

3. 所有 find() 的结果在使用字符串键索引前,应判断返回值是否为 dict,避免空列表引起面板 500 异常。

4. 全局 acme_v2.py 在普通网站表查询不到完整记录时,应回退查询 docker_domain/docker_sites。

5. Docker HTTP/TLS 文件验证应根据站点 ID 获取实际 path + run_path,不应直接把 auth_to 域名 JSON 当成文件路径。

6. 订单文件建议采用原子写入(先写临时文件,再 rename),并在异常时保留旧数据或回滚,避免申请失败导致其他证书订单丢失。

七、本机验证结果

完成以上修复后:

1. 原有 blog.ccnln.com 和 auth.ccnln.com 有效订单保留正常。
2. Docker 域名能正确定位到 docker_sites.id=1,type=proxy。
3. HTTP 验证目录正确为 /www/dk_project/wwwroot/actionlog.ccnln.com/。
4. actionlog.ccnln.com 免费 SSL 证书申请成功。
5. 证书成功自动部署到 Docker 网站。
6. 原有证书订单未再被覆盖。

八、补充说明

该问题发生在宝塔自带的 Docker SSL 申请流程中。DNS、80/443 端口、Nginx 配置、Docker 容器和已部署的外部证书均正常。修正面板 Python 代码后立即可成功签发和部署,可排除用户环境和操作问题。


页: [1]
查看完整版本: 标题:Docker网站申请SSL覆盖原证书订单并报TypeError