命令行工具

curl: (77) error setting certificate verify locations 修复

作者: · 最后核实

报错信息curl: (77) error setting certificate verify locations: CAfile: /etc/ssl/certs/ca-certificates.crt CApath: none

curl: (77) 的意思是:curl 打不开或解析不了它被指定使用的 CA 证书包,因此无法验证任何服务器。 报错里写明了 CAfile 和 CApath,其中一个不存在、是空的、没有读权限,或者被环境变量、命令行选项指到了错误的位置。

快速修复

只要让 curl 指向一个存在、可读的 CA 证书包,报错就会消失。先检查报错里的路径,以及有没有东西覆盖了它:

ls -l /etc/ssl/certs/ca-certificates.crt
env | grep -E 'CURL_CA_BUNDLE|SSL_CERT_FILE|SSL_CERT_DIR'
curl -V
  • 文件不存在: 安装 CA 证书包(见下文)。
  • 环境变量指向不存在的文件: unset CURL_CA_BUNDLE SSL_CERT_FILE,并从 shell 配置、CI 设置或 Dockerfile 里删掉它。
  • 文件存在: 检查权限和内容,head -1 应该输出 -----BEGIN CERTIFICATE-----。

原因

最常见的原因是精简镜像没装 CA 证书包,其次是选项或环境变量给了错误路径。

1. 没装 CA 证书包

精简容器镜像(Debian slim、Alpine、基于 scratch 的镜像)经常没有 ca-certificates(系统的 CA 证书包)。

  • 确认: 报错里的路径不存在。
  • 修复:
apt-get update && apt-get install -y ca-certificates   # Debian/Ubuntu
apk add --no-cache ca-certificates                       # Alpine
dnf install -y ca-certificates                           # RHEL/Fedora/Rocky

国内构建镜像时,先把软件源换成阿里云、清华、中科大等国内镜像,再安装,速度会快很多。

2. 选项或环境变量给了错误路径

--cacert、--capath、CURL_CA_BUNDLE、SSL_CERT_FILE,或者 ~/.curlrc 里的 cacert 行,指向的文件被移走了或者不存在(比如从别的发行版文档里抄来的路径)。

  • 确认: 报错里的 CAfile 和你的发行版默认路径不一样。
  • 修复: 改正或删除这个设置。发行版默认路径:Debian、Ubuntu、Alpine 是 /etc/ssl/certs/ca-certificates.crt,CentOS/RHEL 系是 /etc/pki/tls/certs/ca-bundle.crt。

3. 权限或 SELinux

  • 确认: 文件存在,但 sudo -u www-data cat /路径/文件 失败,或者审计日志里有 SELinux 拒绝记录。
  • 修复: CA 证书包本来就是公开数据,设为所有人可读(chmod 644),用 restorecon 恢复标签。

4. curl 是按别的系统路径编译的

从别的系统复制过来的 curl 二进制、静态编译版,内置的是编译机上的 CA 路径。

  • 确认: curl -v https://example.com 2>&1 | grep CAfile 显示的路径在本机不存在。
  • 修复: 用发行版自带的 curl 包,或者每次都用 --cacert 指定有效的证书包。

5. 证书包是空的或损坏了

更新中断、下载失败都可能留下一个空文件。

  • 修复: 重装软件包,或者执行 update-ca-certificates(Debian/Alpine)、update-ca-trust(RHEL 系)。

各环境修法

PHP、Windows、Docker 和 CI 的修法都是让证书包出现在 curl 实际查找的位置,并让运行 curl 的用户能读到。

PHP / 宝塔: php.ini 里的 curl.cainfo 或 openssl.cafile 指向不存在的 cacert.pem 时,PHP 的 cURL 扩展会报 77。在宝塔“PHP 管理 → 配置文件”里修正路径,或者删掉这两行改用系统证书包;见 PHP cURL error 60。

Windows: Windows 自带的 curl.exe 使用系统证书库,不需要证书包文件。第三方 OpenSSL 版本的 curl 会在可执行文件旁边找 curl-ca-bundle.crt,或读 CURL_CA_BUNDLE,证书包从 curl.se 下载。

Docker: ca-certificates 要装在实际运行 curl 的那个阶段;多阶段构建常常只在构建阶段装了。

CI(GitLab Runner、Jenkins、云效): 检查任务级变量,给某个任务设置的 CURL_CA_BUNDLE 可能被带到其他任务里。

不要这样做

这 3 种做法会关闭校验,或者让访问公网网站出新的错误。

  • 加 curl -k 绕过去。 那次请求就完全不校验了,应该修好证书包。
  • 把证书包指向一张私有根证书。 --cacert 会替换默认列表,访问公网网站会变成 报错 60。私有根证书应该追加到 系统信任库 里。
  • 从网上随便下载一个 cacert.pem。 用系统包管理器,或者 curl.se 发布的证书包。

常见问题

报错 77 是网站的问题吗?

不是。curl 在加载自己的信任库时就失败了,还没看到服务器证书。CA 文件修好之前,这台机器访问任何 HTTPS 地址都会同样失败。

哪些环境变量会改变 CA 路径?

curl 会读 CURL_CA_BUNDLE,基于 OpenSSL 的版本还会读 SSL_CERT_FILE 和 SSL_CERT_DIR。~/.bashrc 里残留的 export、CI 变量、Dockerfile 里指向已删除文件的设置,都是常见原因。

文件明明存在,curl 还是报错?

确认运行 curl 的用户能读这个文件(sudo -u <用户> head -1 /路径/文件),文件是 PEM 文本且不是空的;开启 SELinux 的系统还要确认标签允许调用它的服务读取。宝塔、PHP-FPM 以 www 用户运行时尤其要注意。

资料来源

  1. libcurl error codes
  2. curl: SSL Certificate Verification
  3. curl: CA certificates extracted from Mozilla
  4. PHP: cURL runtime configuration (curl.cainfo)