Getting Started
VM Registry is a container-like management system for virtual machines. It brings the familiar Docker workflow — build, push, pull, and run — to full virtual machines backed by libvirt.
Prerequisites
Before setting up VM Registry, ensure you have the following installed on your system:
- libvirt with QEMU/KVM support
- Go 1.24+ (for server-side components)
- Rust toolchain (for CLI and LSP)
- PostgreSQL 17+ (for the auth server)
- Protobuf compiler (
protoc) for gRPC code generation
TIP
All components include a flake.nix for reproducible development environments. If you use Nix, you can enter each project's devshell with nix develop.
Architecture Overview
VM Registry consists of six main components:
| Component | Language | Role |
|---|---|---|
| vm-registry-cli | Rust | User-facing command-line interface |
| vm-registry-daemon | Go | Local daemon managing VMs via libvirt and gRPC |
| vm-registry-server | Go | OCI-compatible image registry with S3/filesystem storage |
| vm-registry-auth | Go | JWT authentication server with PostgreSQL-backed ACLs |
| vm-registry-lsp | Rust | Language server for VMFile and VMCompose formats |
| vm-registry-proto | Protobuf | Shared gRPC service and message definitions |
The CLI communicates with the daemon over a Unix socket using gRPC. The daemon manages local VM images and libvirt domains, and talks to the remote registry server over HTTP. The auth server issues JWT tokens that the registry server validates.
┌─────────────┐ gRPC/Unix Socket ┌──────────────────┐
│ CLI (Rust) │ ◄────────────────────► │ Daemon (Go) │
└─────────────┘ │ ├─ libvirt │
│ ├─ image storage │
│ └─ gRPC server │
└────────┬─────────┘
│ HTTP
┌────────▼─────────┐
│ Registry Server │
│ (Go, OCI API) │
│ ├─ Filesystem │
│ └─ S3 backend │
└────────┬─────────┘
│ JWT verify
┌────────▼─────────┐
│ Auth Server (Go) │
│ └─ PostgreSQL │
└──────────────────┘Setting Up the Auth Server
The auth server requires PostgreSQL and an RSA key pair for JWT signing.
1. Generate RSA keys
mkdir -p keys
openssl genrsa -out keys/auth.key 4096
openssl rsa -in keys/auth.key -pubout -out keys/auth.pub2. Start PostgreSQL
Use the provided docker-compose.yml in vm-registry-auth:
cd vm-registry-auth
docker compose up -d postgresThis starts PostgreSQL on 127.0.0.1:5432 and runs the init.sql schema automatically.
3. Start the auth server
DATABASE_URL="postgresql://admin:admin@localhost:5432/registry_auth_db" go run server/main.goThe auth server listens on port 4078 and exposes:
POST /register— Register a new userPOST /login— Obtain access and refresh tokensGET /token— Token endpoint for registry authenticationPOST /logout— Revoke refresh tokensGET /health— Health check
Setting Up the Registry Server
The registry server stores VM images and serves them over an OCI-compatible HTTP API.
Filesystem backend (default)
cd vm-registry-server
go run server/main.go -storage filesystem -fs-path ./storageS3-compatible backend
An S3-compatible object store such as MinIO or RustFS can be used:
cd vm-registry-server
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 rustfsadminThe registry server listens on port 8080 by default (configurable with -port).
To enable authentication, copy the auth server's public key:
cp ../vm-registry-auth/keys/auth.pub ./auth.pubSetting Up the Daemon
The daemon manages local VM images and runs VMs through libvirt.
cd vm-registry-daemon
go run server/main.go \
-socket /tmp/vm-registry-daemon.sock \
-registry-url http://127.0.0.1:8080 \
-auth-url http://127.0.0.1:4078Configuration flags
| Flag | Env Variable | Default | Description |
|---|---|---|---|
-socket | VM_REGISTRY_SOCKET_PATH | /var/run/vm-registry.sock | Unix socket path |
-registry-url | VM_REGISTRY_SERVER_URL | — | Registry server URL |
-auth-url | VM_AUTH_SERVER_URL | — | Auth server URL |
-storage | — | filesystem | Storage backend (filesystem or s3) |
-fs-path | VM_REGISTRY_STORAGE_PATH | /var/lib/vm-registry | Local image storage path |
-log-level | VM_REGISTRY_LOG_LEVEL | info | Log level |
Building the CLI
cd vm-registry-cli
cargo build --releaseThe binary is produced at target/release/vm-registry-cli.
Environment variables
| Variable | Default | Description |
|---|---|---|
VM_AUTH_SERVER_URL | http://127.0.0.1:4078 | Authentication server URL |
VM_REGISTRY_SERVER_URL | http://127.0.0.1:8080 | Registry server URL |
VM_REGISTRY_SOCKET_PATH | /tmp/vm-registry-daemon.sock | Daemon socket path |
Quick Start Workflow
1. Register and log in
vmr register -u myuser -p mypassword
vmr login -u myuser -p mypassword2. Import a VM image
Create a VMFile describing your image:
apiVersion: vmregistry.io/v1alpha1
metadata:
name: "myuser/my-vm"
description: "My first VM image"
author: "myuser"
spec:
diskImage: "my-disk.qcow2"
diskFormat: "qcow2"
resources:
cpu: 2
memory: "4GiB"
bootloader:
type: "BIOS"Then import it:
vmr import ./VMFile -t latest3. Run a VM
vmr run myuser/my-vm:latest --vm-name test-vm --cpus 2 --memory-mb 40964. Check running VMs
vmr ps5. Push to the registry
vmr push myuser/my-vm:latest6. Pull from the registry
vmr pull myuser/my-vm:latestNext Steps
- Learn about the full Architecture of VM Registry
- Explore all CLI commands
- Understand the VMFile and VMCompose file formats
- Set up LSP support in your editor