Docker Registry

Lightweight, dependency-free, in-memory Docker Registry HTTP API V2 fake — the protocol docker push, docker pull, and skopeo speak. Implements enough of the distribution spec to list, push and pull manifest metadata for testing.

Default port: 4775

Quick start

import { DockerRegistryServer } from "./services/docker-registry/src/server.js";

const server = new DockerRegistryServer(4775);
await server.start();
// ... run your app/tests ...
await server.stop();

Probe the API and pull a manifest:

await fetch("http://127.0.0.1:4775/v2/"); // 200 {}
await fetch("http://127.0.0.1:4775/v2/library/hello-world/manifests/latest");
// Docker-Content-Digest: sha256:...

Access via MCP / preview URL

No authentication is required (a Bearer token is accepted but never enforced), matching a local insecure registry.

Implemented operations

State is in-memory and ephemeral. All routes live under /v2.

Service & inspection (parlel extensions)

Surface coverage

This emulator faithfully replicates the API surface most application code and agents exercise. Anything below the supported lines is either an intentional design choice for a fast, zero-cost local emulator (✓ By design) or a candidate for a future release (⟳ Roadmap) — never a silent inaccuracy.

Legend: ✅ fully supported · ◐ accepted (stored, not strictly enforced) · ✓ by design · ⟳ on the roadmap.

FeatureStatus
GET /v2/ version check✅ Supported (200 {})
Catalog✅ Supported
Tag list✅ Supported
Manifest HEAD / GET / PUT (+ Docker-Content-Digest)✅ Supported
Blob upload session (POST/PATCH/PUT) + pull✅ Supported
Token/Bearer auth challenge flow (WWW-Authenticate)✓ By design — Not enforced (insecure registry)
Manifest list / OCI index fat manifests◐ Stored as opaque bytes
Cross-repo blob mount / delete / GC⟳ Roadmap
Real layer streaming / content addressing validation◐ Digest taken from ?digest= or computed

Error codes & shapes

Registry error envelope: { "errors": [{ "code": "MANIFEST_UNKNOWN", "message": "..." }] }.

StatusWhen
404unknown repo / manifest / blob
405unsupported method on a route

Manifest

See services/docker-registry/manifest.json:

<!-- parlel:testenv:start -->

Configuration — test.env

Copy these into your test.env (used by the bridge sidecar flow). Tokens are Parlel's seeded test credentials — any non-empty value is accepted by the emulator, so you rarely need to change them. Swap in real credentials only when pointing at the live service in prod.env.

DOCKER_REGISTRY_URL=http://parlel-bridge:4775
REGISTRY_HTTP_ADDR=127.0.0.1:4775
<!-- parlel:testenv:end -->