# Pull Docker images from CloudRepo

> Log in to CloudRepo with a repository token, pull an image by its repositories path, use the same login in CI, and fix a 401, 403 or 404.

The Docker CLI reads CloudRepo like any other registry: log in once, then pull by the image’s full name. This page is for the person whose machine or pipeline pulls images from a repository. To put images there, see [Publish Docker images](/docs/formats/docker.html).

You need a Docker repository and a repository token that reaches it. If you have neither yet: [create a repository](/docs/manage/repositories.html#creating-a-repository) and [create a token](/docs/authenticate/repository-tokens.html). A token that is **Read only** is enough to pull.

## Log in

Log in to your organization’s host, with your email address and the token. Pipe the token to `docker login` on standard input.

**Terminal**

```bash
echo "$CLOUDREPO_TOKEN" | docker login your-org.mycloudrepo.io \
  --username you@example.com \
  --password-stdin
```

Expected: `Login Succeeded`.

- The password is the repository token. Create one on the **Repository Tokens** page of the admin portal.
- Log in to the host alone, `your-org.mycloudrepo.io`, with no path. Docker stores the credential by host and discards any path you add.
- CloudRepo does not check the username, so any value works, but use your email address.

## Pull an image

The image’s name carries the repository, after a literal `/repositories/`:

**Terminal**

```bash
docker pull your-org.mycloudrepo.io/repositories/your-repo/my-app:1.0.0
```

The name is `<organization>.mycloudrepo.io/repositories/<repository>/<image>:<tag>`. You logged in to the bare host, but you pull from the `/repositories/` path, and the login names no repository, so a good login tells you nothing about whether the name is right.

Expected: Docker prints `Status: Downloaded newer image` for the name you pulled.

## In CI

Use the same login, with the token from your CI’s secret store:

**Terminal**

```bash
echo "$CLOUDREPO_TOKEN" | docker login your-org.mycloudrepo.io --username you@example.com --password-stdin
```

Store the token as a secret (a GitHub Actions secret, a GitLab CI variable) and never commit it. The name is yours to choose: the admin portal’s ready-made GitHub Actions and GitLab CI snippets call it `CLOUDREPO_PASSWORD`, after Docker’s password field. The value is the same repository token, not a CloudRepo password.

When a `docker build` installs private packages from CloudRepo, give the token to that step as a build secret, never as a build argument: Docker records build arguments in the image’s history. The [Docker repositories](/docs/formats/docker.html#installing-packages-from-cloudrepo-in-a-docker-build) page shows how, for Maven, pip and npm.

## What the registry does not serve

CloudRepo does not list a repository’s images: `/v2/_catalog` answers `405 UNSUPPORTED`. See what a repository holds in the admin portal.

## When Docker answers 401, 403 or 404

- **`docker login` answers 401 Unauthorized.** Use a repository token as the password. Check on the **Repository Tokens** page that it has not been revoked or expired. A token from `npm login` (`crn_v1_`) works only on the npm repository it was created for, and Docker refuses it.
- **`docker pull` answers 403 or `denied`.** The token does not reach this repository. A token reaches only the repositories ticked when it was created, so use one that includes it.
- **`docker pull` cannot find the repository or the image.** Check that the name carries the literal `repositories/` segment, as above, and that the image and tag exist in that repository.

More: [Repository tokens](/docs/authenticate/repository-tokens.html), for every client’s credential; [Proxy repositories](/docs/consume/proxy-repositories.html), to pull Docker Hub or another registry through CloudRepo; [Docker repositories](/docs/formats/docker.html), for pushing, groups and the other settings.

---

The page: https://www.cloudrepo.io/docs/consume/docker.html
