Docker Repositories

This page covers using the Docker CLI with CloudRepo private Docker repositories.

Hosted at CloudRepo — see private Docker registry hosting for plans and pricing.

Docker Client Configuration

Overview

CloudRepo Docker repositories implement the standard Docker Registry HTTP API V2 and the companion Token Authentication Specification. Any Docker-compatible client (docker, podman, nerdctl, Buildah, Kaniko, Skopeo, etc.) connects with no special configuration beyond docker login.

The credential CloudRepo recommends for Docker — and the one this guide uses throughout — is a Generic repository token (crp_v1_*) created in the admin portal. It is repo-scoped, revocable on its own, and rotates independently of anyone’s password. The Docker CLI presents the token via HTTP Basic auth to mint short-lived Bearer scope-tokens at request time; the Bearer is held in the CLI’s memory only and never appears on disk. See Docker Two-Tier Model below for the protocol details.

This page will help you get started by helping you setup a CloudRepo Docker repository.

Pre-Requisites

Note

In the Connection Settings of your repository we provide specific configuration information for your repository.

Before you can use CloudRepo with Docker you’ll need to ensure that you have created a Docker Repository as well as a Repository User in the CloudRepo Admin Portal.

If you haven’t done this yet, please see the following instructions for doing so:

Note

Owners are not exempt: an org-owner’s email and portal password will not log in at the Docker registry. Create a repository token and use that instead.

Configuration

Step 1: Create a Repository Token

Sign in to https://admin.cloudrepo.io as a member who can mint tokens and open Repository Tokens in the left-hand navigation, then Create token. Choose the Generic format — it is the format the Docker registry accepts — name the token, select the repositories it may reach, and set a scope. The token value is shown ONCE — copy it immediately. Tokens are repo-scoped and rotate independently from your portal password.

Note

Generic tokens begin with crp_v1_. The npm format (crn_v1_) is accepted only on npm repositories and will not authenticate at the Docker registry.

Step 2: docker login

Authenticate the Docker CLI against your CloudRepo registry:

docker login [your-organization-name].mycloudrepo.io

The CLI prompts for username (the email of the account that minted the token) and password (the repository token from Step 1). The credentials are stored in ~/.docker/config.json as the auth field (base64-encoded email:token pair).

Important

Use the repository token as the password value at docker login, not the password you sign in to the admin portal with. An organization owner’s portal password is refused outright here (see Creating Users for the credential model), so for an owner a token is the only way in.

Important

Log in to the host only — the image reference is where the repository goes.

docker login takes [your-organization-name].mycloudrepo.io and nothing more. The pull and push references in the next steps add /repositories/[your-repository-name]/. The two commands deliberately look different from each other.

Adding the repository path to docker login does not produce an error. Docker stores exactly one credential per host and discards any path you type, so the command reports Login Succeeded and gives you no signal that the path was dropped. Log in to the host; let the image reference carry the repository.

Step 3: Tag and Push

Tag a local image with your CloudRepo registry’s repository path, then push. Note the literal repositories/ segment — it is part of the reference, and it is the same segment Maven, npm, and PyPI repositories are addressed under:

docker tag my-app:1.0.0 [your-organization-name].mycloudrepo.io/repositories/[your-repository-name]/my-app:1.0.0
docker push [your-organization-name].mycloudrepo.io/repositories/[your-repository-name]/my-app:1.0.0

Behind the scenes, the Docker CLI performs the V2 auth handshake: it issues an unauthenticated GET /v2/ ping and replays the request with HTTP Basic auth. Where the registry challenges with WWW-Authenticate: Bearer, the CLI first exchanges those Basic credentials for a short-lived Bearer scope-token and uses that Bearer for the manifest and blob uploads. Either way the credential you supply is the same: your email and a Generic repository token.

Pulling Images from CloudRepo

To pull an image:

docker pull [your-organization-name].mycloudrepo.io/repositories/[your-repository-name]/my-app:1.0.0

The same docker login credentials apply — and the same asymmetry: you authenticated against the bare host, but you pull the /repositories/ path. Public repositories accept unauthenticated pulls; private repositories require authenticated pulls per the same V2 token-auth flow.

CI/CD Integration

For non-interactive environments (GitHub Actions, GitLab CI, CircleCI, Jenkins, Buildkite, etc.), feed the repository token to docker login via standard input:

echo "$CLOUDREPO_TOKEN" | docker login [your-organization-name].mycloudrepo.io \
  --username [your-minting-account-email] \
  --password-stdin

The --password-stdin form keeps the token out of process listings and shell history. Store the token as a CI secret (GitHub Actions secrets.CLOUDREPO_TOKEN, GitLab CI CI_VARIABLE, etc.) — never commit it to a repository.

The variable name is yours to choose. The admin portal’s ready-made GitHub Actions and GitLab CI snippets call it CLOUDREPO_PASSWORD because it is supplied at Docker’s password prompt; the value is the same repository token either way.

Docker Two-Tier Token Model

The Docker Registry V2 specification defines a two-tier credential model. CloudRepo implements it per spec; this section explains how the two tiers relate to your workflow:

Tier 1 — L3 repository token (customer-managed)

  • The crp_v1_* token you create in the admin portal

  • Long-lived (you choose the expiration when you create it)

  • Stored in ~/.docker/config.json and in CI secret stores

  • Listed, rotated, and revoked from the admin portal

  • This is the credential you manage

Tier 2 — L3 Bearer Scope-Token (server-issued, ephemeral)

  • A short-lived JWT minted by the registry’s /v2/token endpoint

  • Lifetime ~5 minutes

  • Held in the Docker CLI’s memory only — never on disk

  • Bound to a specific operation scope — repository:repositories/<repo>/<image>:pull or repository:repositories/<repo>/<image>:push,pull

  • You never see this token; the CLI manages it transparently

Note

The literal repositories/ appears inside the scope string. The OCI grammar is repository:<name>:<actions>, and <name> is the image name exactly as the client computed it from your reference — to Docker, repositories is simply the first component of the name, not a path segment it knows to strip.

This matters when you are debugging: a 403 quotes the scope it evaluated. If the scope in the error has no repositories/ component, the reference that produced it was missing the segment — see the troubleshooting entry above.

The registry-level endpoints do not carry the marker: the /v2/ ping and the token endpoint itself, whose realm stays https://<your-organization-name>.mycloudrepo.io/v2/token. The marker describes a repository, and neither of those names one.

(/v2/_catalog is not implemented — it answers 405 UNSUPPORTED. Use the admin portal to see what a repository holds.)

Revoking the L3 repository token in the admin portal cascades: subsequent Bearer mint attempts fail, and active CI jobs stop authenticating within the Bearer TTL window (~5 minutes worst case). This is the canonical “rotate to invalidate” workflow for Docker — no separate Bearer revocation surface exists or is needed.

Troubleshooting

``docker login`` returns 401 Unauthorized

  • Verify the username is the email of the account that minted the token

  • Verify you used the repository token as the password, not your admin-portal password

  • If you are the organization owner, your portal password will not work here at all — mint a repository token

  • Verify the repository token has not been revoked or expired (check the admin portal)

  • Verify the token is bound to the repository you’re trying to push to (repository tokens are repo-id-scoped)

``docker push`` returns 403 Forbidden after a successful login

  • The authenticated member’s role does not have write permission to the target repository

  • In the admin portal, verify the member’s role is full-access (not read-only) for the repository

``docker push`` or ``docker pull`` fails to find the repository

  • Check the reference carries the literal repositories/ segment: <org>.mycloudrepo.io/repositories/<repo>/<image>:<tag>. Omitting it is the most common mistake, because docker login does not use it

  • A successful docker login tells you nothing about this — the login names no repository at all, so it cannot warn you that the reference is malformed

``docker pull`` of a public image returns 401

  • If the repository is marked public, no authentication is required — docker pull should succeed without prior docker login

  • If you’re seeing 401 on a public repository, verify the repository’s public flag is enabled in the admin portal

Group Docker Repositories

A group repository is a single address that resolves against several member repositories in a priority order you set. It is how you give a team one registry URL that serves images kept in more than one repository.

Create it in the admin portal with Docker as the format and Group as the kind, then add member repositories and order them. On a pull, CloudRepo tries each member in priority order and serves the first that has the image.

The reference shape does not change. A group is addressed exactly like a local repository — same host, same repositories/ segment:

docker pull [your-organization-name].mycloudrepo.io/repositories/[your-group-repo]/my-app:1.0.0

A typical arrangement is one address for developers and two repositories behind it: app-images holding what your team builds, and vendor-images holding third-party images you have vetted and pushed yourself. Group team-registry lists them in that order, and developers configure one host and one repository name.

Important

Group repositories are read-only. docker push to a group is rejected — a group has no storage of its own, so there is no member the registry could correctly choose to write to. Push to the member repository directly and the image is visible through the group immediately.

Permissions still apply per member repository: a group never widens access. A user who cannot read a member repository does not see its images through the group.

Docker Repository Settings

Public vs Private Repositories

Docker repositories can be marked public (anonymous read access) or private (authenticated access only). Public repositories appear in the public CloudRepo registry and can be pulled by anyone without credentials.

Toggle the public flag in the Repository Settings of your Docker Repository.

Other Settings

All Standard Settings apply.