NIX BINARY CACHE SERVER — RUST

Bunker

Bunker

Version 1.00Source on GitHub

OVERVIEW

Bunker is "The Secure Nix Cache Server" (GitHub repo description; README title: "Qompass AI Bunker: The Secure Nix Cache Server"): a Rust workspace (`bunker`, `client`, `server`, `token`) that stores and serves Nix store paths as a binary cache, with chunked, compressed, deduplicated NAR storage and signed uploads.

HOW IT WORKS

  1. 1`bunkerd` loads its TOML config (`-f/--config`, `--mode` default `monolithic`), runs database migrations, then runs the API server and the periodic garbage collector together.
  2. 2A client logs in (`bunker login`) and records the server endpoint and token in `$XDG_CONFIG_HOME/bunker/config.toml` (Unix, mode 0600) or `%APPDATA%\bunker\config.toml` (Windows).
  3. 3`bunker cache create` creates a named cache on the server; `bunker use` writes the local Nix configuration so Nix trusts and uses that cache.
  4. 4On push, the full client reads paths, NARs, and signatures from the local Nix store through `libnixstore`, asks the server which paths are missing (`get_missing_paths`), and uploads the missing NARs (`upload_path`).
  5. 5The server chunks large NARs (content-defined chunking), compresses the chunks, and stores them in local or S3 storage, indexed in its database (PostgreSQL recommended for production), so duplicate chunks are stored once.
  6. 6Nix clients fetch narinfo and NAR data from the cache over the binary-cache API; garbage collection runs on the configured interval (default 12 hours) and per-cache retention periods decide what is deleted.
  7. 7Release binaries can be stored and served next to the cache as artifacts (store-free), which is also the workflow the no-Nix subset client (Windows / Android-Termux) supports, together with `cache` and `login`.
How it works, step by step — each step as the project's own documentation states it.

CONCEPTS

SIGNED UPLOAD → CHUNKED STORE → VERIFIED FETCHLOCAL NIX STOREpaths + NARsbunker pushmissing paths onlySIGN NARINFOEd25519 cache keyCACHE — bunkerdserves narinfo + NARINSIDE THE SERVERCHUNKINGcontent-defined · 16/64/256 KiBCOMPRESS + DEDUPzstd · identical chunks stored onceSTORAGE + INDEXlocal or S3 · database indexNIX CLIENTfetching a pathFETCHnarinfo + NAR dataVERIFY SIGNATUREagainst the trusted public keySUBSTITUTE — OR REFUSEan untrusted cache is never usedTRUST IS CHECKED ON EVERY FETCH — NOT ASSUMED FROM THE URL
Bunker's cache flow: the client uploads only the paths the server is missing, the server chunks (content-defined), compresses, and deduplicates the NARs, and Nix clients fetch narinfo whose Ed25519 signature they verify before substituting anything — an untrusted cache is refused, not used.

CONFIGURATION

OptionDefaultWhat it does
listen[::]:8080Socket address to listen on
allowed-hosts`[]` (all `Host` headers allowed if unconfigured/empty; must be configured for production)Allowed `Host` headers
api-endpointunset (synthesized from the client's `Host` header if unconfigured)Canonical API endpoint exposed in `cache-config` responses; must end with a slash
soft-delete-caches`false` (commented in template)Soft-delete caches instead of removing them from the database
require-proof-of-possession`true` (commented in template)Require fully uploading a NAR even if it exists in the global cache
database.url`%database_url%` (template placeholder)Database connection URL; PostgreSQL recommended for production
database.heartbeat`false` (commented in template)Send a heartbeat query every minute
storage.typelocalStorage type: `local` or `s3`
storage.path`%storage_path%` (template placeholder)Local storage directory
storage.region` / `storage.bucket` / `storage.endpointunset (commented in template)S3 region, bucket, and custom S3-compatible endpoint
AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEYread from environment if `storage.credentials` is unsetS3 credentials source
chunking.nar-size-threshold65536Minimum NAR size to trigger chunking (0 disables, 1 chunks all)
chunking.min-size16384Preferred minimum chunk size, in bytes
chunking.avg-size65536Preferred average chunk size, in bytes
chunking.max-size262144Preferred maximum chunk size, in bytes
compression.typezstdCompression type: `none`, `brotli`, `zstd`, or `xz`
compression.levelunset (example `8` commented in template)Compression level
garbage-collection.interval12 hoursGC frequency; zero disables automatic GC (manual: `bunkerd --mode garbage-collector-once`)
garbage-collection.default-retention-periodzero (time-based GC disabled by default)Default retention period; can be enabled per cache
artifacts.max-size`1073741824` (1 GiB)Maximum size of a single artifact upload, in bytes
jwt.token-bound-issuer` / `jwt.token-bound-audiencesunset (commented in template)If set, received JWTs must match this `iss` / contain one of these `aud` values
BUNKER_SERVER_TOKEN_ED25519_SECRET_BASE64alternative source for `jwt.signing.token-ed25519-secret-base64`Base64-encoded Ed25519 PEM private key for JWT signing
BUNKER_SERVER_TOKEN_ED25519_PUBKEY_BASE64alternative source for `jwt.signing.token-ed25519-pubkey-base64`Base64-encoded Ed25519 PEM public key (verify-only)
`default-server` (client)unsetDefault server to connect to
`servers.<name>.endpoint` (client)no defaultServer endpoint recorded per named server
`servers.<name>.token` / `token-file` (client)no defaultAccess token inline, or path to a token file

CONTROLS

ActionControl
Log in to a serverbunker login
Configure Nix to use a cachebunker use
Push store paths to a cache`bunker push` (full build only; subset builds refuse with a Nix-store error)
Watch the local store and push new paths`bunker watch-store` (full build only)
Manage caches`bunker cache create` / `bunker cache info` (plus configure/destroy subcommands in the same module)
Manage release artifactsbunker artifact push` / `pull` / `rm
Compute a path's closure`bunker get-closure` (hidden subcommand; full build only)
Generate shell completionsbunker gen-completions <shell>
Run the server`bunkerd -f/--config <file> [-l/--listen <addr>] [--mode monolithic\
Make an access token (server admin)bunkerd-adm make-token
Generate a hybrid signing key (server admin)bunkerd-adm generate-hybrid-key
Show the hybrid public key (server admin)bunkerd-adm show-hybrid-public-key
Build the subset (no-Nix) clientcargo build -p bunker-client --no-default-features --release

NOT COVERED

- The README itself is mostly boilerplate (quick-start/about/funding); the functional description above is sourced from the config template, CLI source, and `docs/platforms.md`, not from a narrative README section. - The exact binary names `bunkerd` / `bunkerd-adm` are inferred from the server/adm crate layout and the template's own reference to `bunkerd --mode garbage-collector-once`; the template confirms `bunkerd`, the adm binary name was not spelled out in a file read. - The sandbox clone (`~/workspace/repos/bunker`) is older than GitHub HEAD (it lacks `client/src/command/artifact.rs` and `server/src/api/v1/artifacts.rs`); rows citing primo/GitHub files reflect the newer tree. - Per-subcommand flags for `push`, `login`, `use`, and `artifact` (beyond the subcommand names) were not enumerated for this pack.

REFERENCES

  1. Nix manual — Binary cache substituterThe binary-cache model Bunker implements: narinfo metadata, signatures, and the trusted-public-keys check a client applies before trusting a cache.
  2. RFC 8032 — Edwards-Curve Digital Signature Algorithm (EdDSA)The signature scheme behind the cache signing keys — verification is the fail-closed step in the diagram.