Skip to content

Server

Go

The VM Registry Server (vm-registry-server) is a centralized image registry that stores and serves VM images over an OCI-inspired HTTP API. It is a stateless HTTP server that delegates all persistence to a pluggable storage backend — either the local filesystem or an S3-compatible object store.

Overview

The registry server is the remote counterpart to the daemon's local image store. When users push images with vmr push, the daemon uploads blobs and manifests to this server. When users pull images with vmr pull, the daemon downloads them from here. Authentication is enforced via JWT tokens issued by the Auth Server.

text
Daemon ──HTTP──► Registry Server ──► Storage Backend (Filesystem / S3)

                       └── JWT verify ──► Auth Server public key

Running the Server

bash
cd vm-registry-server
go run server/main.go [FLAGS]

Configuration Flags

FlagDefaultDescription
-port8080HTTP server port
-storagefilesystemStorage backend: filesystem or s3
-fs-path./storageFilesystem storage directory path
-s3-bucketS3 bucket name (required for S3 backend)
-s3-regionus-east-1S3 region
-s3-endpointS3-compatible endpoint URL (for MinIO, RustFS, etc.)
-s3-access-keyS3 access key (or set AWS_ACCESS_KEY_ID)
-s3-secret-keyS3 secret key (or set AWS_SECRET_ACCESS_KEY)
-s3-skip-bucket-creationfalseSkip automatic bucket creation on startup

Filesystem Backend

bash
go run server/main.go -storage filesystem -fs-path ./storage

S3-Compatible Backend

The server supports any S3-compatible object store. The provided docker-compose.yml includes a RustFS instance for local development:

bash
docker compose up -d rustfs

go run server/main.go \
  -storage s3 \
  -s3-bucket vm-images \
  -s3-endpoint http://127.0.0.1:9000 \
  -s3-access-key rustfsadmin \
  -s3-secret-key rustfsadmin

Compatible object stores include:

StoreNotes
AWS S3Set -s3-region and credentials via flags or environment variables
MinIOSet -s3-endpoint to the MinIO API URL
RustFSIncluded in the project's docker-compose.yml for development
Any S3-compatibleUse -s3-endpoint and -s3-skip-bucket-creation if needed

Authentication

The registry server validates JWT tokens using the auth server's RSA public key. To enable authentication, place the public key file at ./auth.pub relative to the server's working directory:

bash
cp ../vm-registry-auth/keys/auth.pub ./auth.pub

When a valid public key is found, the server wraps all API routes with authentication middleware that:

  1. Extracts the Authorization: Bearer <token> header from incoming requests
  2. Validates the JWT signature against the RSA public key
  3. Parses the token claims to extract scope information (repository pattern + allowed actions)
  4. Enforces that the token's scope grants the required permissions for the requested operation

If the public key file is not found or cannot be loaded, the server starts with authentication disabled and logs a warning. This is useful for local development but should not be used in production.

API Routes

The registry exposes a versioned HTTP API under the /v1 prefix.

Blob Operations

MethodPathDescription
HEAD/v1/<repository>/blobs/<digest>Check if a blob exists and retrieve its size
GET/v1/<repository>/blobs/<digest>Download a blob by its content digest
PUT/v1/<repository>/blobs/<digest>Upload a blob with a known digest
PATCH/v1/<repository>/blobs/uploads/<uuid>Upload a blob chunk (chunked upload)
DELETE/v1/<repository>/blobs/<digest>Delete a blob

Manifest Operations

MethodPathDescription
GET/v1/<repository>/manifests/<reference>Download a manifest by tag or digest
PUT/v1/<repository>/manifests/<reference>Upload or update a manifest
DELETE/v1/<repository>/manifests/<reference>Delete a manifest

Internal Structure

The server is organized into the following internal packages:

PackageResponsibility
internal/apiHTTP router setup and route registration
internal/api/v1V1 API handler implementations for blob and manifest operations
internal/api/v2Reserved for future API version
internal/authJWT authentication middleware — public key loading, token validation, scope parsing and enforcement
internal/configServer configuration from command-line flags
internal/logsStructured logging with HTTP request/response logging middleware
internal/modelsData models for blobs, manifests, media types, configs, and storage interfaces
internal/storageStorage interface definition
internal/storage/filesystemFilesystem storage backend implementation
internal/storage/s3S3 storage backend implementation

Storage Interface

Both storage backends implement a common Storage interface defined in internal/storage. This makes them interchangeable through configuration without any code changes. The interface covers:

  • Blob existence checks (by digest)
  • Blob read and write operations
  • Manifest read and write operations (by repository and reference)
  • Manifest and blob deletion
  • Listing operations for repositories and tags

Filesystem Layout

When using the filesystem backend, data is stored under the configured -fs-path:

bash
./storage/
├── blobs/
   └── sha256/
       └── <digest>              # content-addressed blob data
└── manifests/
    └── <repository>/
        └── <reference>/
            └── manifest.json     # image manifest

S3 Layout

When using the S3 backend, objects are stored in the configured bucket with a similar key structure:

text
s3://<bucket>/
├── blobs/sha256/<digest>
└── manifests/<repository>/<reference>/manifest.json

Data Models

Manifest

A manifest is a JSON document that describes an image by referencing its component blobs:

FieldDescription
schemaVersionManifest schema version
mediaTypeMIME type of the manifest
configDescriptor pointing to the image configuration blob
layersList of descriptors pointing to layer blobs (disk images)

Blob

A blob is an opaque, content-addressed data object identified by its SHA-256 digest. Blobs can represent:

  • Disk images — The actual VM disk files (qcow2, raw, iso)
  • Config blobs — JSON documents containing image metadata (CPU, memory, bootloader settings parsed from VMFile)

Media Types

The server uses custom media types to distinguish between different content types:

Media TypeDescription
application/vnd.vmregistry.manifest.v1+jsonImage manifest
application/vnd.vmregistry.config.v1+jsonImage configuration
application/vnd.vmregistry.disk.v1Disk image layer

Middleware Stack

Incoming requests pass through the following middleware chain (outermost first):

  1. HTTP Logging — Logs method, path, status code, and response time for every request
  2. JWT Authentication — Validates bearer tokens and enforces scope-based access control (when enabled)
  3. Route Handler — The actual API handler for the matched route

Dependencies

DependencyPurpose
github.com/golang-jwt/jwt/v5JWT token parsing and validation
github.com/google/uuidUUID generation for upload sessions
github.com/minio/minio-go/v7S3 client for the S3 storage backend
github.com/mattn/go-isattyTerminal detection for log formatting

Built with Go and Rust