Two in the morning, and the CI pipeline is failing. The code hasn't changed; the tests passed yesterday. The upstream forge returned a 429 for a source-archive request — the tag is there, the sources are there, but you can't download them. The build is stuck until someone else's server recovers.
Sound familiar? A forge can go down, move, hit a rate limit, or simply be unreachable from your network. An ordinary local cache saves one machine and one package manager. For everything else, you need a separate release endpoint that you control.
I first ran into this about five years ago: GitHub blocked a repository that my projects depended on. The dependencies broke instantly. That same evening I wrote a minimal server that downloaded the releases I needed and served them locally. Over the years, that evening script grew into yggvault — a full-fledged tool with several ecosystems, built-in storage, and a mesh network. More on the motivation in Why release mirroring matters.
What yggvault does
The operator lists specific projects and their upstream URLs in the configuration. yggvault pulls releases from GitHub, GitLab, Bitbucket, Gitea, and other git forges, validates the archives, stores them in local storage (SQLite + Pebble), and republishes them through a set of ready-made endpoints:
- Go module proxy — standard
GOPROXY-compatible routes, including major-version paths and optional rewriting of import paths to the mirror's address; - Composer v2 repository — metadata and packages for PHP projects;
- Universal archives —
.zipand.tar.gzwith a stable root directory; - JSON API and OpenAPI — for automation;
- Atom feeds — a global and a per-project update feed;
- Web UI — catalog, package pages, install snippets, hashes, and archive links.
The project grew out of a need for Go modules and manual archive downloads — Composer came along for the ride, and universal archives cover the standardized download schemes of Zig, Bazel, and anything else distributed as .zip/.tar.gz.
One process, one binary. No JVM, no external database, no object storage. The hot artifact cache is rebuilt from storage on demand — if the upstream is temporarily unavailable, already-stored versions keep being served. Pipeline details are in Import and refresh pipeline, storage details in Storage internals.
What it looks like
The web interface shows a catalog of mirrored projects with versions, source information, hashes, install commands, and direct archive links. The same data is available programmatically: JSON API, OpenAPI document, Go proxy routes, Composer metadata, Atom feeds. The full route map is in Web/API routes and nested mode.
Try it in three steps
1. Download the binary
Prebuilt builds on GitHub Releases for Linux, macOS, Windows, and FreeBSD (10 platforms, including ARM and RISC-V).
2. Write a minimal config
~12 lines of YAML:
web:
server:
domain: "modules.localhost"
mode: "single"
single:
proto: "http"
listen: "127.0.0.1:8080"
storage:
dir: "./data"
release_mirrors:
errors: "https://github.com/go-faster/errors"
Or generate a preset: yggvault --make-preset minimal
3. Run it:
yggvault config.yml
After the first sync: curl http://modules.localhost:8080/errors/releases.json
The mirror is live. Browser, curl, go get, composer require — one endpoint, several formats.
How it differs from existing tools
| yggvault | Athens | Nexus OSS | Satis | wget --mirror | |
|---|---|---|---|---|---|
| Ecosystems | Go + Composer + universal | Go | 20+ | Composer | Raw files |
| External dependencies | None | None | JVM, opt. PostgreSQL | PHP | None |
| Model | Selected projects | Transparent proxy | Full registry / proxy | Static repo | File copy |
| Web UI | Yes | No | Yes | No | No |
| Mesh network | Yggdrasil | — | — | — | — |
| Federation | Brother mirrors | — | Enterprise license | — | — |
yggvault fills the niche of a compact, multi-ecosystem mirror for specific projects: a single binary with no external dependencies, structured endpoints for package managers,...
SUNsung
Roni Bandini
Yann Guidon / YGDES
Mauro Riva
Freak(leeqingshui)