imgsrv is a disk image artifact server for publishing versioned image formats
and materializing them for consumers such as Incus. It is intended to accept
authenticated image uploads, record immutable release versions and image
variants, store downloadable image formats in a content-addressed store, expose
direct download APIs, and optionally expose metadata that Incus can consume as a
remote image source.
Status: early implementation. The service entrypoint, HTTP API scaffold, durable upload intake, PostgreSQL catalog store, filesystem image storage, and direct CAS blob serving exist; publication worker logic has not landed yet. The current product direction is captured in the architecture docs.
- DESIGN.md — historical design draft for the initial service shape.
- cmd/imgsrv — Go service entrypoint.
- internal/cli — Cobra/Viper command wiring.
- internal/httpapi — HTTP API adapter.
- docs/ — Docusaurus source for https://imgsrv.meigma.dev.
- scripts/configure_github_repo.py — helper for applying .github/repository-settings.toml.
- .github/workflows/ci.yml — CI entry point.
Prerequisites:
- Go
1.26.2. - Node.js
22.22.2, matching .nvmrc. npm.- Moon, for repository-level task orchestration.
Run the Go checks:
go test ./...
go build -o bin/imgsrv ./cmd/imgsrvRun tagged integration tests, including catalog store provider coverage and the Testcontainers-backed end-to-end upload harness:
moon run root:test-integrationRun the scaffolded API locally:
IMGSRV_POSTGRES_URL=postgres://user:pass@localhost:5432/imgsrv?sslmode=disable \
go run ./cmd/imgsrv startPostgreSQL is the required catalog store. Provide the connection URL with
--postgres-url or IMGSRV_POSTGRES_URL; startup applies embedded database
migrations before binding the HTTP server.
The server keeps node-local upload scratch under .imgsrv/uploads/ by default.
Completed tus uploads are copied into shared image storage under
.imgsrv/storage/ingress/jobs/...; published immutable bytes live under
.imgsrv/storage/cas/sha256/.... Use --data-dir or IMGSRV_DATA_DIR for
local scratch, and --storage-dir or IMGSRV_STORAGE_DIR for the shared
filesystem storage root.
POST /api/images currently initializes durable resumable upload intake. It
accepts JSON publication metadata, records an uploading upload session, and
returns the session ID plus the tus creation URL and required tus metadata
header value. Clients then upload qcow2 bytes through /api/uploads/tus/.
When tusd reports completion, imgsrv claims the local tus file into job-owned
shared pending storage, records a queued publication job plus accepted source
artifact, and exposes the job URL through
GET /api/uploads/{upload_session_id}. It does not authenticate requests yet,
run a worker, promote bytes into published CAS storage, or publish
catalog-visible image records. Use --max-upload-bytes or
IMGSRV_MAX_UPLOAD_BYTES to enforce an optional qcow2 upload size cap; the
default 0 leaves the app-level cap disabled.
The current service can serve sharded immutable CAS blob paths:
/cas/sha256/{first-two-hex}/{64-char-sha256}
The direct CAS handler is an implementation path behind the service. User-facing
downloads should go through semantic API download routes so imgsrv remains the
policy boundary for visibility, authentication, redirects, and backend behavior.
Server logging defaults to plaintext slog records at info verbosity. Use
--log-format json or IMGSRV_LOG_FORMAT=json for JSON logs, and use
--verbosity debug|info|warn|error or IMGSRV_VERBOSITY to control the minimum
log level.
OpenTelemetry HTTP metrics are exposed on a separate Prometheus scrape listener
at 127.0.0.1:9464/metrics by default. Use --metrics-listen or
IMGSRV_METRICS_LISTEN to change the listener address, --metrics-path or
IMGSRV_METRICS_PATH to change the path, and --metrics-listen '' to disable
the metrics listener. Application packages should receive the configured
telemetry providers and create package-scoped meters through Telemetry.Meter.
Install and run the documentation site locally:
cd docs
npm ci
npm run startBuild the documentation site:
cd docs
npm run buildRun the repository CI contract locally:
moon ci --summary minimal- Project docs: https://imgsrv.meigma.dev
- Repository: https://github.com/meigma/imgsrv
- Architecture docs: docs/docs/architecture
- Historical design draft: DESIGN.md
Use GitHub Discussions for questions and general discussion. Use GitHub Issues for non-security bug reports and feature requests.
Do not report vulnerabilities in public channels. See SECURITY.md.
See CONTRIBUTING.md for contribution guidelines, local setup expectations, and pull request workflow.
See SECURITY.md for supported versions and the private vulnerability reporting path.
imgsrv is licensed under either of:
at your option.