命令行工具
pip SSL: CERTIFICATE_VERIFY_FAILED:不用 --trusted-host 的修法
Could not fetch URL https://pypi.org/simple/requests/: There was a problem confirming the ssl certificate: HTTPSConnectionPool(host='pypi.org', port=443): Max retries exceeded with url: /simple/requests/ (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate')))There was a problem confirming the ssl certificate ... CERTIFICATE_VERIFY_FAILED 的意思是:pip 连上了 PyPI 或你配置的软件源,但无法验证它的证书。 在公司网络里,几乎都是 HTTPS 解密代理的根证书 pip 不认识;其他情况是 pip 太旧、私有仓库用了内部 CA,或者镜像源配置有问题。
快速修复
最快的修法是把 pip 升级到 24.2 以上,让它读取系统证书库;不能升级就用 --cert 指定证书包。先看 pip 版本,因为 pip 24.2 及以后会同时信任操作系统证书库:
python -m pip --version
python -m pip install --upgrade pip --cert /path/to/ca-bundle.pem
如果你有包含代理根证书或内网根证书的证书包,把它写进配置长期生效:
pip config set global.cert /path/to/ca-bundle.pem
# 或者只在当前 shell / CI 任务中生效
export PIP_CERT=/path/to/ca-bundle.pem
ca-bundle.pem 应该是系统证书包(如 /etc/ssl/certs/ca-certificates.crt)再追加你的根证书(PEM 格式),因为 --cert 会替换默认列表,而不是在它基础上追加。
原因
办公电脑上最常见的是公司的 HTTPS 解密代理,其次是私有仓库的内部 CA 和过旧的 pip。
1. 公司的 HTTPS 解密代理
办公电脑上的 pip 证书报错,大多来自公司上网行为管理或安全网关用公司根证书重新签名 HTTPS,见企业 SSL 解密。
- 确认:
openssl s_client -connect pypi.org:443 -servername pypi.org </dev/null | grep issuer显示的是公司名或安全厂商,而不是公开 CA。 - 修复: 在 IT 已把根证书装进系统证书库的电脑上,升级到 pip 24.2 以上;或者用
--cert/PIP_CERT指定根证书。
2. 私有仓库使用内部 CA
Nexus、Artifactory、devpi 等私有 Python 仓库,证书常由公司内部 CA 签发。
- 确认: 报错里的主机名是内网地址,而不是 pypi.org。
- 修复: 把内部根证书加到
--cert使用的证书包里,或者装进系统证书库并使用能读取它的 pip 版本。
3. pip 或 Python 太旧
老版本 pip 自带的 certifi 也很旧,缺少较新的根证书。
- 确认:
pip --version显示的是好几年前的版本,报错的站点使用较新的根证书。 - 修复: 升级 pip(必要时加
--cert)。已停止维护的 Python 版本,直接升级 Python。
4. 镜像源证书链有问题
镜像站没发中间证书时,浏览器能打开,pip 却会失败。
- 确认: 把镜像域名输入 SSL 检测工具检查。
- 修复: 换一个配置正确的镜像源,或者反馈给镜像维护方。清华 TUNA、阿里云、腾讯云、华为云的 PyPI 镜像都提供 HTTPS,配置时直接用
https://地址:
pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/
5. 代理地址写错
如果报错是 WRONG_VERSION_NUMBER 或 EOF occurred in violation of protocol,而不是证书错误,问题出在代理配置,见 WRONG_VERSION_NUMBER。
各环境修法
根证书装进系统证书库后,pip 24.2 以上会直接读取;旧版本和容器里用 PIP_CERT 或 --cert 指定证书包。
Windows: pip 24.2 以上会自动信任域策略下发的根证书,旧版本需要 --cert。用户配置文件在 %APPDATA%\pip\pip.ini。
macOS: pip 24.2 以上通过 truststore 读取钥匙串,公司根证书要在“系统”钥匙串里并设为信任。
Linux: 用 update-ca-certificates(Debian/Ubuntu)或 update-ca-trust(CentOS/RHEL 系)安装根证书,然后依靠 pip 24.2 以上的系统证书支持,或者把 PIP_CERT 指向系统证书包。
Docker / CI:
COPY company-root.crt /usr/local/share/ca-certificates/
RUN update-ca-certificates
ENV PIP_CERT=/etc/ssl/certs/ca-certificates.crt
RUN python -m pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt
其他安装工具: conda 有自己的 ssl_verify 设置,可以填 CA 证书包路径;uv 可以用 --native-tls 使用系统证书库,或用 SSL_CERT_FILE 指定证书包。
不要这样做
这 4 种做法要么让安装的包失去来源验证,要么在下次升级时失效。
--trusted-host pypi.org --trusted-host files.pythonhosted.org。 这是转载最多的答案,它关闭的是这些主机的证书校验,而软件包是你随后要执行的代码。- 把镜像地址改成
http://再配合--trusted-host。 国内不少旧教程这样写,结果是每个下载在网络上都能被读取和替换。 --use-deprecated=legacy-certs想“回到以前的样子”。它去掉了系统证书库支持,通常会让代理问题更严重。- 直接修改 site-packages 里 certifi 的
cacert.pem。 下次pip install --upgrade certifi会悄悄覆盖它,应该维护一份自己的证书包文件。
常见问题
为什么浏览器能打开 pypi.org,pip 却报错?
浏览器信任操作系统证书库里的根证书,包括 IT 部门下发的公司代理根证书;pip 24.2 之前只信任自带的 certifi 列表,里面只有公开根证书。升级 pip,或者用 --cert 指定包含公司根证书的证书包。
pip 自己就报错,没法升级 pip 怎么办?
升级时临时指定一次证书包:python -m pip install --upgrade pip --cert /path/to/ca-bundle.pem。升级到 24.2 以上后,pip 会同时读取系统证书库。手头没有证书包文件的话,从系统证书库导出代理根证书(PEM 格式),追加到 certifi 证书文件的副本里。
很多教程让加 --trusted-host,安全吗?
不安全。pip 的说明是:把主机标记为可信,即使它没有有效的 HTTPS 甚至没有 HTTPS。之后 pip 会安装这个主机(或任何冒充它的人)返回的任何东西。只适合可信内网里的明文 HTTP 私有源,绝不要用于 PyPI 或公开镜像。
证书和镜像源配置写在哪里最省事?
执行 pip config set global.cert /path/to/ca-bundle.pem,会写进用户配置文件(Linux、macOS 是 pip.conf,Windows 是 pip.ini)。镜像源同理:pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple。pip config debug 可以列出 pip 读取的所有配置文件和各项值的来源。