Documentation

OCI

OCI is the container-image ecosystem: the format of container images and the HTTP protocol clients such as Docker and Podman use to pull and push them. An image is a small tree, not one file: a manifest (a JSON document listing an image's parts), a config blob, and one or more layer blobs (the filesystem, gzip-compressed). Every part is a blob addressed by the sha256 of its bytes; a mutable tag (latest, 1.25) points at a manifest's digest. peryx serves OCI over the distribution spec that registries (Docker Hub, GHCR, ECR, Artifactory) implement.

How OCI concepts map to peryx

peryx describes every ecosystem with one neutral vocabulary; here is how the container terms you already know line up with it. In OCI contexts peryx uses the container term; the neutral name is what the same idea is called across ecosystems (see the index model and glossary).

Container termperyx conceptWhat it is
registryindexthe endpoint a client points at; a cached index proxies one upstream
repositoryprojectone image name, like library/alpine
tagversiona mutable name (latest, 1.25) pointing at a manifest digest
image (manifest+blobs)artifactwhat you pull: a manifest, a config blob, and layers, not one file
layer / blobfileone content-addressed piece, stored once and shared across images
digest (sha256:…)content addressthe sha256 that names and verifies every stored object
pushupload / publishputting an image into a hosted index
pulldownloadfetching an image through peryx
pull-through cachecached (role)a read-through proxy of one upstream registry

The role names (cached, hosted, virtual) and shadowing are peryx's own, the same in every ecosystem.

The roles for OCI

The three index roles map onto OCI like this:

  • cached: a read-through cache of an upstream registry. On a miss peryx pulls the manifest or blob from upstream (running the bearer-token handshake the registry requires), verifies its digest, stores it, and serves it; later pulls come from disk. Point one at Docker Hub, GHCR, or any /v2/ registry.
  • hosted: a store you push your own images to. Blobs stream into the content-addressed store and are verified on commit; manifests are kept byte-for-byte so their digest is stable. Pushing needs a token (below).
  • virtual: an ordered stack of members served under one name, where your hosted images shadow same-named upstream ones: a pull of a name you have published serves your image, and anything you have not published falls through to the upstream. This is the dependency-confusion defense, applied to containers.

The wire protocol

Container clients speak the distribution spec over a /v2/ API. peryx serves it directly:

  • GET /v2/: the version check every client pings first; peryx answers 200 with Docker-Distribution-API-Version: registry/2.0, or a 401 Bearer challenge when an index restricts access.
  • Manifests: GET|HEAD|PUT|DELETE /v2/<name>/manifests/<tag-or-digest>. peryx keeps a manifest byte-for-byte and addresses it by the sha256 of those exact bytes, so the Docker-Content-Digest a client verifies matches.
  • Blobs: GET|HEAD|DELETE /v2/<name>/blobs/<digest>, plus the upload dance (POST/PATCH/PUT /v2/<name>/blobs/uploads/…) for push. peryx deduplicates blob bytes across indexes and requires a repository link before serving them. For a cross-repo mount, peryx verifies the source link and pull access before it adds the target link. Concurrent pulls of one uncached layer share a single upstream fetch.
  • Tags: GET /v2/<name>/tags/list.
  • Token auth: peryx serves its own Bearer token realm. GET /v2/ challenges when an index restricts access, GET /v2/token mints a repository-scoped JWT, and resource routes enforce it, so docker login validates a credential. It runs the upstream's own handshake for you when it pulls through.

For the full standards map, see standards.

Set me up

OCI images are content-addressed and immutable, so <name> in /v2/<name>/… carries the index route as a prefix: an index at route dockerhub proxying Docker Hub serves library/alpine as dockerhub/library/alpine. Configure a proxy and a hosted store:

# peryx.toml
[[index]]
name = "dockerhub"
route = "dockerhub"
ecosystem = "oci"
cached = "https://registry-1.docker.io"

[[index]]
name = "images"
route = "images"
ecosystem = "oci"
hosted = true
upload_token = "<token>"

Assume peryx is then running at 127.0.0.1:4433.

Docker and Podman trust a loopback registry (localhost, 127.0.0.0/8) over plain HTTP with no configuration, so on the same host it just works. Reaching peryx over the network, or from Docker Desktop's VM, needs either TLS (the production path: a real or ACME certificate, no client flag) or the client's insecure-registry setting. crane and podman take a per-command flag; the snippets below show it.

Pull

docker pull 127.0.0.1:4433/dockerhub/library/alpine:latest
podman pull --tls-verify=false 127.0.0.1:4433/dockerhub/library/alpine:latest
crane pull --insecure 127.0.0.1:4433/dockerhub/library/alpine:latest alpine.tar

Push

Pushing needs a hosted index with an upload_token. peryx accepts any username; the token is the Basic-auth password.

docker login 127.0.0.1:4433 -u _ -p <token>
docker tag alpine 127.0.0.1:4433/images/alpine:latest
docker push 127.0.0.1:4433/images/alpine:latest
podman login --tls-verify=false 127.0.0.1:4433 -u _ -p <token>
podman push --tls-verify=false alpine 127.0.0.1:4433/images/alpine:latest
crane auth login 127.0.0.1:4433 -u _ -p <token>
crane push --insecure alpine.tar 127.0.0.1:4433/images/alpine:latest

In practice

  • Performance

    peryx as a Docker Hub pull-through cache next to the distribution reference registry and zot: cold and warm pulls, layer throughput, and a pull fleet.

  • Docker Hub names and upstream auth

    Why Docker Hub official images live under library/, why registry-mirror mode never needed the prefix, and what an upstream 401 now tells an operator.

  • How peryx scopes and serves manifest reads

    Why a by-digest manifest pull is authorized against the requesting repository, not the shared content store, and why an index tag can hand back a single-platform image.

  • Why peryx is a Bearer token realm

    How the OCI token flow works, why an anonymous token can pull a public repository, and why turning on the challenge does not break anonymous pulls.

  • Why peryx serves the registry the way it does

    Why peryx accepts an upstream manifest digest in a non-sha256 algorithm, why it validates a referrers subject up front, and why cancelling an upload reclaims its bytes while a 416 hands back the coordinates to resume.

  • Tutorials

    Learning-oriented lessons for pulling and pushing container images through peryx.

  • How-to guides

    Task-oriented recipes for the OCI ecosystem: run a container registry, push and pull, delete images.

  • Reference

    Information-oriented specifications for the OCI ecosystem: the /v2/ distribution-spec HTTP endpoints peryx serves.

  • Migration

    Move to peryx from another container registry: cloud registries and self-hosted registries.

On this page