> For the complete documentation index, see [llms.txt](https://yeasy.gitbook.io/docker_practice/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://yeasy.gitbook.io/docker_practice/di-yi-bu-fen-ru-men-pian/06_repository/6.3_registry_auth.md).

# 6.3 私有仓库高级配置

上一节我们搭建了一个具有基础功能的私有仓库，本小节我们来使用 `Docker Compose` 搭建一个拥有权限认证、TLS 的私有仓库。

新建一个文件夹，以下步骤均在该文件夹中进行。

## 6.3.1 准备站点证书

如果你拥有一个域名，国内各大云服务商均提供免费的站点证书。你也可以使用 `openssl` 自行签发证书。

这里假设我们将要搭建的私有仓库地址为 `docker.domain.com`，下面我们介绍使用 `openssl` 自行签发 `docker.domain.com` 的站点 SSL 证书。

第一步创建 `CA` 私钥。

```bash
$ openssl genrsa -out "root-ca.key" 4096
```

第二步利用私钥创建 `CA` 根证书请求文件。

```bash
$ openssl req \
          -new -key "root-ca.key" \
          -out "root-ca.csr" -sha256 \
          -subj '/C=CN/ST=Shanxi/L=Datong/O=Your Company Name/CN=Your Company Name Docker Registry CA'
```

> 以上命令中 `-subj` 参数里的 `/C` 表示国家，如 `CN`；`/ST` 表示省；`/L` 表示城市或者地区；`/O` 表示组织名；`/CN` 通用名称。

第三步配置 `CA` 根证书，新建 `root-ca.cnf`。

```bash
[root_ca]
basicConstraints = critical,CA:TRUE,pathlen:1
keyUsage = critical, nonRepudiation, cRLSign, keyCertSign
subjectKeyIdentifier=hash
```

第四步签发根证书。

```bash
$ openssl x509 -req  -days 3650  -in "root-ca.csr" \
               -signkey "root-ca.key" -sha256 -out "root-ca.crt" \
               -extfile "root-ca.cnf" -extensions \
               root_ca
```

第五步生成站点 `SSL` 私钥。

```bash
$ openssl genrsa -out "docker.domain.com.key" 4096
```

第六步使用私钥生成证书请求文件。

```bash
$ openssl req -new -key "docker.domain.com.key" -out "site.csr" -sha256 \
          -subj '/C=CN/ST=Shanxi/L=Datong/O=Your Company Name/CN=docker.domain.com'
```

第七步配置证书，新建 `site.cnf` 文件。

```bash
[server]
authorityKeyIdentifier=keyid,issuer
basicConstraints = critical,CA:FALSE
extendedKeyUsage=serverAuth
keyUsage = critical, digitalSignature, keyEncipherment
subjectAltName = DNS:docker.domain.com, IP:127.0.0.1
subjectKeyIdentifier=hash
```

第八步签署站点 `SSL` 证书。

```bash
$ openssl x509 -req -days 750 -in "site.csr" -sha256 \
    -CA "root-ca.crt" -CAkey "root-ca.key"  -CAcreateserial \
    -out "docker.domain.com.crt" -extfile "site.cnf" -extensions server
```

配套 demo 中的 [`ssl/README.md`](https://github.com/yeasy/docker_practice/blob/master/06_repository/demo/ssl/README.md) 只保留本地生成证书的占位说明，真实私钥和证书不应提交到仓库。 这样已经拥有了 `docker.domain.com` 的网站 SSL 私钥 `docker.domain.com.key` 和 SSL 证书 `docker.domain.com.crt` 及 CA 根证书 `root-ca.crt`。

新建 `ssl` 文件夹并将 `docker.domain.com.key` `docker.domain.com.crt` `root-ca.crt` 这三个文件移入，删除其他文件。

> **安全提示**：这些私钥和证书应在本地或受控部署环境中生成，不要提交进 Git 仓库。示例目录只保留占位说明，运行前请按上面的步骤重新生成。

## 6.3.2 配置私有仓库

私有仓库默认的配置文件位于 `/etc/docker/registry/config.yml`，我们先在本地编辑 `config.yml`，之后挂载到容器中。

```yaml
log:
  accesslog:
    disabled: true
  level: debug
  formatter: text
  fields:
    service: registry
    environment: staging
storage:
  delete:
    enabled: true
  cache:
    blobdescriptor: inmemory
  filesystem:
    rootdirectory: /var/lib/registry
auth:
  htpasswd:
    realm: basic-realm
    path: /etc/docker/registry/auth/nginx.htpasswd
http:
  addr: :5000
  host: https://docker.domain.com
  headers:
    X-Content-Type-Options: [nosniff]
  http2:
    disabled: false
  tls:
    certificate: /etc/docker/registry/ssl/docker.domain.com.crt
    key: /etc/docker/registry/ssl/docker.domain.com.key
health:
  storagedriver:
    enabled: true
    interval: 10s
    threshold: 3
```

## 6.3.3 生成 http 认证文件

```bash
$ mkdir auth

$ docker run --rm \
    --entrypoint htpasswd \
    httpd:2.4-alpine \
    -Bbn username password > auth/nginx.htpasswd
```

> 将上面的 `username` `password` 替换为你自己的用户名和密码。
>
> **安全提示**：上述命令会将密码明文暴露在 shell 历史记录和进程列表中。生产环境建议使用交互式方式输入密码（不带 `-b` 参数），或通过环境变量/文件传入。 配套 demo 的 [`auth/README.md`](https://github.com/yeasy/docker_practice/blob/master/06_repository/demo/auth/README.md) 仅说明本地生成步骤，生成的 `auth/nginx.htpasswd` 已被忽略，不应提交。

> **版本说明**：使用 `httpd:2.4-alpine` 基于 Apache 2.4 的精简镜像。如需其他版本，可替换为 `httpd:latest` 或指定具体版本号如 `httpd:2.4.58-alpine`。

## 6.3.4 编辑 Docker Compose 配置

编辑 `compose.yaml` (或 `docker-compose.yml`) 配置如下：

```yaml
services:
  registry:
    image: registry:2
    ports:
      - "443:5000"
    volumes:
      - ./:/etc/docker/registry
      - registry-data:/var/lib/registry

volumes:
  registry-data:
```

本书配套的 `06_repository/demo/` 也采用同样约定：容器内 registry 监听 `:5000`，宿主机通过 `443:5000` 暴露 HTTPS 服务。这样可以避免在容器内占用特权端口，同时仍让客户端使用 `https://docker.domain.com` 访问。

> **版本说明**：Compose 配置中明确指定 `registry:2` 版本。生产环境建议固定具体补丁版本（如 `registry:2.8.x`），并在新部署时评估 Distribution 3.x；不要使用 `latest`，以保证部署的可重复性。

## 6.3.5 修改 Hosts 文件

编辑 `/etc/hosts`

```bash
127.0.0.1 docker.domain.com
```

## 6.3.6 启动

```bash
$ docker compose up -d
```

这样我们就搭建好了一个具有权限认证、TLS 的私有仓库，接下来我们测试其功能是否正常。

## 6.3.7 测试私有仓库功能

由于自行签发的 CA 根证书不被系统信任，所以我们需要将 CA 根证书 `ssl/root-ca.crt` 移入 `/etc/docker/certs.d/docker.domain.com` 文件夹中。

```bash
$ sudo mkdir -p /etc/docker/certs.d/docker.domain.com

$ sudo cp ssl/root-ca.crt /etc/docker/certs.d/docker.domain.com/ca.crt
```

登录到私有仓库。

```bash
$ docker login docker.domain.com
```

尝试推送、拉取镜像。

```bash
$ docker pull ubuntu:24.04

$ docker tag ubuntu:24.04 docker.domain.com/username/ubuntu:24.04

$ docker push docker.domain.com/username/ubuntu:24.04

$ docker image rm docker.domain.com/username/ubuntu:24.04

$ docker pull docker.domain.com/username/ubuntu:24.04
```

> **版本说明**：示例使用 `ubuntu:24.04`，这是最新 LTS 版本。推送到私有仓库时保持了原有的版本标签，建议生产环境明确指定镜像版本号。 如果我们退出登录，尝试推送镜像。

```bash
$ docker logout docker.domain.com

$ docker push docker.domain.com/username/ubuntu:24.04

no basic auth credentials
```

发现会提示没有登录，不能将镜像推送到私有仓库中。

## 6.3.8 注意事项

如果你本机占用了 `443` 端口，你可以配置 [Nginx 代理](https://docs.docker.com/registry/recipes/nginx/)，这里不再赘述。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://yeasy.gitbook.io/docker_practice/di-yi-bu-fen-ru-men-pian/06_repository/6.3_registry_auth.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
