调用portainer.io API报SSL CERTIFICATE_VERIFY_FAILED错误如何解决
报错根因
这个SSL证书校验失败的触发逻辑非常明确:
- requests库默认对所有HTTPS请求开启服务端证书合法性校验,会校验证书是否由受信任的根CA签发、是否和访问域名匹配
- Portainer默认启动时会自动生成一份自签名SSL证书用来监听9443 HTTPS端口,这份自签名证书不在你的操作系统/Python环境的受信任根证书列表里,校验直接不通过,请求还没发到业务接口就被拦截了
修复方案
根据你当前的使用场景选对应方案即可,不需要从零手动创建SSL证书。
本地开发/内网测试场景
优先选最快能跑通的方案:
- 快速调试方案:直接关闭requests的证书校验,同时屏蔽关闭校验后触发的不安全请求警告。注意原示例代码还有一处参数错误:Portainer的
/api/auth接口要求接收JSON格式请求体,直接传参给data会默认以表单格式提交,会触发400错误,需要把参数传给json关键字。修正后可运行代码如下:
import requests import urllib3 # 关闭证书校验对应的警告提示 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) URL = "https://localhost:9443" data_auth = { "password": "your_portainer_password", "username": "your_portainer_username" } url_auth = f"{URL}/api/auth" # verify=False关闭证书校验,json参数自动设置Content-Type为application/json auth_response = requests.post(url_auth, json=data_auth, verify=False) print(auth_response.json())
- 不想完全关闭校验的方案:从Portainer部署路径下导出默认的自签名公钥证书
cert.pem(容器部署时证书默认存放在容器内/certs目录,绑定挂载到宿主机的话直接从挂载目录取即可),放到脚本同级目录,请求时指定证书路径即可,不需要关闭校验:
auth_response = requests.post(url_auth, json=data_auth, verify="./cert.pem")
生产环境场景
禁止在生产代码中使用verify=False,会完全丧失HTTPS的防中间人攻击能力,按以下方式处理:
- 替换Portainer默认自签名证书:将你申请到的可信CA签发的证书(公网可信证书、企业内部CA签发的证书均可)命名为
cert.pem,对应私钥命名为key.pem,挂载到Portainer的/certs目录覆盖默认文件,重启Portainer后服务端返回的就是受信任证书,requests默认校验逻辑即可正常通过,不需要额外传参。 - 反向代理层终止HTTPS:在Portainer前端部署Nginx、Caddy等反向代理,由反向代理持有可信SSL证书对外提供HTTPS服务,反向代理和Portainer之间走内网HTTP 9000端口通信(9000端口不对外暴露即可),此时直接请求反向代理的HTTPS地址即可正常通过证书校验。
额外排查点
如果按上述方案操作后还是报证书错误,检查以下两点:
- 确认你访问的地址和证书绑定的域名一致,比如证书签的是
portainer.yourdomain.com就不要用localhost或者IP访问,否则会触发域名不匹配的校验错误 - 如果你是在公司内网环境,确认网络没有开启HTTPS中间人代理,这类代理会替换所有站点的证书,需要把公司内网的根证书加到requests的证书信任列表里
内容的提问来源于stack exchange,提问作者iheb salah
相关产品推荐
相关产品推荐

