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 portalLong-lived (you choose the expiration when you create it)
Stored in
~/.docker/config.jsonand in CI secret storesListed, 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/tokenendpointLifetime ~5 minutes
Held in the Docker CLI’s memory only — never on disk
Bound to a specific operation scope —
repository:repositories/<repo>/<image>:pullorrepository:repositories/<repo>/<image>:push,pullYou 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(notread-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, becausedocker logindoes not use itA successful
docker logintells 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 pullshould succeed without priordocker loginIf 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.