Docker Registry HTTP API V2 - Technical Documentation
This document describes the Docker Registry HTTP API V2 implementation in Nitro Repo. Use this to understand how Docker clients interact with the registry or to implement custom clients.
API Endpoints
All Docker Registry endpoints are prefixed with /v2/.
Version Check
Endpoint: GET /v2/
Returns the Docker Registry API version. This endpoint typically does not require authentication.
Response:
HTTP/1.1 200 OK
Docker-Distribution-API-Version: registry/2.0
Content-Type: application/json
{}Upload Initialization
Endpoint: POST /v2/{storage}/{repository}/{name}/blobs/uploads/
Initiates a blob (layer or config) upload session.
Request:
POST /v2/docker/docker-test/my-app/blobs/uploads/
Authorization: Basic base64(username:password)Response:
HTTP/1.1 202 Accepted
Location: /v2/docker/docker-test/my-app/blobs/uploads/{uuid}
Range: 0-0
Docker-Upload-UUID: {uuid}Blob Upload (Chunked)
Endpoint: PATCH /v2/{storage}/{repository}/{name}/blobs/uploads/{uuid}
Uploads a chunk of blob data.
Request:
PATCH /v2/docker/docker-test/my-app/blobs/uploads/{uuid}
Content-Type: application/octet-stream
Content-Range: 0-1023
Content-Length: 1024
[binary data]Response:
HTTP/1.1 202 Accepted
Location: /v2/docker/docker-test/my-app/blobs/uploads/{uuid}
Range: 0-1023Blob Upload Completion
Endpoint: PUT /v2/{storage}/{repository}/{name}/blobs/uploads/{uuid}?digest={digest}
Completes a blob upload and verifies the digest.
Request:
PUT /v2/docker/docker-test/my-app/blobs/uploads/{uuid}?digest=sha256:abc123...
Content-Length: 0Response:
HTTP/1.1 201 Created
Location: /v2/docker/docker-test/my-app/blobs/sha256:abc123...
Content-Length: 0
Docker-Content-Digest: sha256:abc123...Blob Download
Endpoint: GET /v2/{storage}/{repository}/{name}/blobs/{digest}
Downloads a blob by its digest.
Request:
GET /v2/docker/docker-test/my-app/blobs/sha256:abc123...Response:
HTTP/1.1 200 OK
Content-Type: application/octet-stream
Content-Length: 12345
Docker-Content-Digest: sha256:abc123...
[binary data]Blob Existence Check
Endpoint: HEAD /v2/{storage}/{repository}/{name}/blobs/{digest}
Checks if a blob exists without downloading it.
Response:
HTTP/1.1 200 OK
Content-Length: 12345
Docker-Content-Digest: sha256:abc123...Manifest Upload
Endpoint: PUT /v2/{storage}/{repository}/{name}/manifests/{reference}
Uploads an image manifest. The reference can be a tag or digest.
Request:
PUT /v2/docker/docker-test/my-app/manifests/latest
Content-Type: application/vnd.docker.distribution.manifest.v2+json
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"config": {
"mediaType": "application/vnd.docker.container.image.v1+json",
"size": 1234,
"digest": "sha256:config123..."
},
"layers": [
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 5678,
"digest": "sha256:layer123..."
}
]
}Response:
HTTP/1.1 201 Created
Location: /v2/docker/docker-test/my-app/manifests/latest
Docker-Content-Digest: sha256:manifest123...Manifest Download
Endpoint: GET /v2/{storage}/{repository}/{name}/manifests/{reference}
Downloads an image manifest by tag or digest.
Request:
GET /v2/docker/docker-test/my-app/manifests/latest
Accept: application/vnd.docker.distribution.manifest.v2+jsonResponse:
HTTP/1.1 200 OK
Content-Type: application/vnd.docker.distribution.manifest.v2+json
Docker-Content-Digest: sha256:manifest123...
{manifest JSON}Tags List
Endpoint: GET /v2/{storage}/{repository}/{name}/tags/list
Lists all tags for an image.
Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"name": "my-app",
"tags": ["latest", "v1.0.0", "v1.0.1"]
}Authentication
Docker clients use HTTP Basic Authentication. Nitro Repo supports two authentication methods:
Username + Password
Standard user authentication:
docker login your-registry.com
Username: alice
Password: her_passwordThis sends:
Authorization: Basic base64(alice:her_password)Username + Token (Recommended)
Use an auth token as the password. The username can be anything:
docker login your-registry.com
Username: token
Password: nr_abc123...your_auth_tokenThis sends:
Authorization: Basic base64(token:nr_abc123...your_auth_token)When Nitro Repo receives Basic auth:
- First attempts to verify as username/password
- If that fails, treats the password field as an auth token
- This allows token-based authentication with any username
Authentication Challenge
When authentication is required, Nitro Repo issues a Docker-compliant bearer challenge:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="https://your-registry.com/v2/token",service="your-registry.com",scope="repository/{storage}/{repository}:pull,push"
Docker-Distribution-API-Version: registry/2.0The Docker client then requests a bearer token from /v2/token, supplying the scope that was provided in the challenge. Nitro Repo validates the user's credentials (username/password, session, or automation token), issues a short-lived bearer token scoped to the requested repository actions, and the client retries the original request with:
Authorization: Bearer <token>This flow matches the Docker Registry specification, allowing standard Docker CLIs and OCI clients to authenticate without additional configuration.
Authorization Behavior
Nitro Repo's Docker repositories follow this authorization model:
When Auth is Disabled
- Pull (GET/HEAD): Allowed without authentication
- Push (PUT/POST/DELETE): Requires authentication
When Auth is Enabled
- All Operations: Require authentication
This matches standard package repository behavior where public registries allow anonymous pulls but require auth for pushes.
Content Addressing
Docker uses content-addressable storage with SHA256 digests:
sha256:1234567890abcdef...All blobs (layers, configs) and manifests are stored by their digest, ensuring:
- Immutability: Content cannot be changed once stored
- Deduplication: Identical content is stored only once
- Integrity: Content is verified against its digest
Media Types
Nitro Repo supports these media types:
Docker Manifest V2
application/vnd.docker.distribution.manifest.v2+jsonapplication/vnd.docker.distribution.manifest.list.v2+json
OCI Image Format
application/vnd.oci.image.manifest.v1+jsonapplication/vnd.oci.image.index.v1+json
Layer Media Types
application/vnd.docker.image.rootfs.diff.tar.gzipapplication/vnd.oci.image.layer.v1.tar+gzip
Error Responses
Errors follow the Docker Registry API V2 error format:
{
"errors": [
{
"code": "MANIFEST_INVALID",
"message": "manifest invalid",
"detail": "Invalid manifest JSON"
}
]
}Common error codes:
BLOB_UNKNOWN- Blob not foundBLOB_UPLOAD_INVALID- Invalid upload sessionMANIFEST_INVALID- Invalid manifest formatMANIFEST_UNKNOWN- Manifest not foundNAME_INVALID- Invalid repository nameTAG_INVALID- Invalid tag nameUNAUTHORIZED- Authentication requiredDENIED- Permission denied
Path Rewriting
Nitro Repo uses a special path rewriting mechanism to maintain compatibility with Docker clients while preserving its internal URL structure.
Docker clients expect: /v2/{name}/... Nitro Repo internally uses: /repositories/{storage}/{repository}/...
The router automatically rewrites:
/v2/{storage}/{repository}/{*path}
→ /repositories/{storage}/{repository}/v2/{*path}This allows Docker clients to use natural URLs while Nitro Repo maintains its organized structure.