Documentation
Everything you need to push your first image, wire up CI and manage access tokens.
Quick start
The registry implements the OCI Distribution Specification, so any compatible client works: Docker, Podman, containerd, Buildah, Skopeo, Helm 3.8+ and ORAS.
# 1. log in with an access token echo "$NB_TOKEN" | docker login cdn.nordbaysys.com -u "$NB_TEAM" --password-stdin # 2. tag and push docker tag app-backend:latest cdn.nordbaysys.com/myteam/app-backend:v2.4.1 docker push cdn.nordbaysys.com/myteam/app-backend:v2.4.1 # 3. pull anywhere docker pull cdn.nordbaysys.com/myteam/app-backend:v2.4.1
Authentication
All endpoints require authentication. There is no anonymous access, including for metadata requests. The registry uses the standard token flow:
- The client calls
GET /v2/and receives401with aWWW-Authenticate: Bearerchallenge. - The client exchanges its credentials for a short-lived bearer token at
/token. - Subsequent requests carry
Authorization: Bearer <token>.
Access tokens are created in the console under Team → Access tokens. A token is scoped to one team and to one of three roles:
| Role | Pull | Push | Delete | Typical use |
|---|---|---|---|---|
| read | yes | no | no | Cluster nodes, deploy jobs |
| write | yes | yes | no | CI pipelines |
| admin | yes | yes | yes | Retention jobs, migrations |
Tokens are shown once. Rotate them at least every 90 days; expired tokens return 401 with error code UNAUTHORIZED.
CI/CD
GitLab CI
build:
image: docker:27
services: [docker:27-dind]
script:
- echo "$NB_TOKEN" | docker login cdn.nordbaysys.com -u "$NB_TEAM" --password-stdin
- docker build -t cdn.nordbaysys.com/$NB_TEAM/$CI_PROJECT_NAME:$CI_COMMIT_SHORT_SHA .
- docker push cdn.nordbaysys.com/$NB_TEAM/$CI_PROJECT_NAME:$CI_COMMIT_SHORT_SHA
Kubernetes pull secret
kubectl create secret docker-registry nordbay \ --docker-server=cdn.nordbaysys.com \ --docker-username="$NB_TEAM" \ --docker-password="$NB_TOKEN"
API reference
Registry endpoints follow the OCI Distribution Specification v1.1. Management endpoints live under /api/v1/ and accept the same bearer tokens.
| Method | Path | Description |
|---|---|---|
| GET | /v2/ | API version check and auth challenge |
| GET | /v2/<name>/tags/list | List tags of a repository |
| GET · HEAD | /v2/<name>/manifests/<ref> | Fetch a manifest by tag or digest |
| GET · HEAD | /v2/<name>/blobs/<digest> | Fetch a layer or config blob |
| POST · PATCH · PUT | /v2/<name>/blobs/uploads/ | Chunked or monolithic blob upload |
| GET | /api/v1/repositories | List repositories of the team |
| GET | /api/v1/usage | Storage and transfer usage for the billing period |
| POST | /api/v1/retention/run | Trigger a retention policy run |
Limits
| Limit | Team | Business |
|---|---|---|
| Layer size | 10 GB | 50 GB |
| API requests | 600 / min per token | 3000 / min per token |
| Concurrent uploads | 20 | 100 |
| Upload session lifetime | 24 h | 72 h |
Requests over the limit receive 429 Too Many Requests with a Retry-After header.
Errors
Errors use the standard registry envelope:
{"errors":[{"code":"UNAUTHORIZED","message":"authentication required","detail":null}]}
| Status | Code | Meaning |
|---|---|---|
| 401 | UNAUTHORIZED | Missing, expired or invalid token |
| 403 | DENIED | Token role does not allow the operation |
| 404 | NAME_UNKNOWN | Repository does not exist in this team |
| 429 | TOOMANYREQUESTS | Rate limit exceeded |
Still stuck? Write to support@nordbaysys.com.