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.
TIP
Looking to install VM Registry? See the Installation page for quick install scripts, per-distro instructions, and Nix options.
Development Prerequisites
If you want to build VM Registry from source or contribute to development, you'll need the following tools 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. For the full setup guide, see the Auth Server component page. The quick version:
# 1. Generate RSA keys
mkdir -p keys
openssl genrsa -out keys/auth.key 4096
openssl rsa -in keys/auth.key -pubout -out keys/auth.pub
# 2. Start PostgreSQL
cd vm-registry-auth
docker compose up -d postgres
# 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 endpoints for registration, login, token issuance, logout, and health checks.
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/vmr.
Environment variables
These are read by the CLI (vmr) and override the active context:
| Variable | Default | Description |
|---|---|---|
VM_REGISTRY_SERVER_URL | http://127.0.0.1:8080 | Registry server URL |
VM_REGISTRY_SOCKET_URL | unix:/run/vm-registry-daemon.sock | Daemon socket URL |
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