根本原因是Docker daemon仅信任系统CA池,不读取挂载的自签名证书;须将根证书复制到宿主机/etc/docker/certs.d/域名:端口/ca.crt并重启docker服务。

自建Registry启用HTTPS时证书不被客户端信任
根本原因不是证书没配,而是Docker daemon默认只认系统CA池,不读取容器内或挂载的自签名证书。哪怕你把 ca.crt 拷进镜像、挂到 /etc/ssl/certs/,Docker client 仍会报 x509: certificate signed by unknown authority。
实操上必须让 daemon 显式信任——不是改客户端,是改服务端所在机器的 daemon 配置:
- 把你的根证书(比如
domain.crt)复制到宿主机的/etc/docker/certs.d/your-registry.example.com:5000/ca.crt(路径必须严格匹配 registry 域名+端口) - 重启 daemon:
systemctl restart docker,注意不是 restart container - 验证:运行
curl -v https://your-registry.example.com:5000/v2/看是否返回200 OK;再试docker login your-registry.example.com:5000
常见错误:把证书放错目录(比如放到 /usr/local/share/ca-certificates/ 后忘了 update-ca-certificates),或漏掉端口号导致目录名不匹配。
Docker client 访问私有仓库提示“no basic auth credentials”
这不是证书问题,是认证流程断在了第一环:Docker daemon 根本没把你的 ~/.docker/config.json 中的凭据发出去。典型触发场景是 registry 启用了 TLS 但没配好反向代理的 header 透传。
关键检查点:
- 确认 registry 容器启动时加了
--env REGISTRY_AUTH=htpasswd和对应REGISTRY_AUTH_HTPASSWD_PATH挂载 - 如果前面套了 Nginx,必须透传
Authorizationheader:proxy_pass_request_headers on;,且禁用proxy_set_header Authorization "";这类清空操作 - 登录命令必须带端口:
docker login your-registry.example.com:5000,否则凭据存到默认的 Docker Hub keyring 下,不会复用
容易被忽略:Nginx 默认会 strip 掉部分 header,Authorization 正好在默认黑名单里,需显式放开。
registry镜像升级后push失败,报“unknown blob”或“manifest invalid”
这是存储后端兼容性断裂导致的。v2.7+ 默认启用 schema2 manifest 格式,而老版本(如 v2.6.x)写入的 storage layer 可能含 schema1 元数据,新 registry 读取时校验失败。
临时解法(不推荐长期用):
- 降级 registry 镜像到
registry:2.6.2 - 或启动时加参数强制兼容:
-e REGISTRY_STORAGE_MAINTENANCE_READONLY=enabled+ 手动清理_manifests目录下旧结构(风险高,慎用)
正解是迁移前做一次 manifest 升级转换:docker run --rm -v /path/to/registry:/var/lib/registry registry:2.7.1 /bin/registry garbage-collect --dry-run /etc/docker/registry/config.yml,确认无误后再去真正执行。
使用Let’s Encrypt证书时Docker login反复失败
ACME 证书本身没问题,问题出在 Let’s Encrypt 的中间证书链不完整。很多自动化工具(如 certbot)默认只下载 leaf cert,没带 ISRG Root X1 或 R3 中间链,导致 Docker daemon 验证时无法拼出完整信任链。
验证方式很简单:
- 运行
openssl s_client -connect your-registry.example.com:5000 -showcerts - 看输出里是否包含两段以上
BEGIN CERTIFICATE—— 至少要 leaf + R3 两个 - 若只有 1 段,用
cat fullchain.pem privkey.pem > domain.crt生成完整证书文件,再按第一个副标题的方式重装到/etc/docker/certs.d/...
这个坑特别隐蔽:浏览器访问正常,curl 也正常,唯独 Docker client 报错。因为它的 TLS 栈比 curl 更严格,不自动补全缺失的中间证书。










