NIX BINARY CACHE SERVER — RUST

Bunker
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`bunkerd` loads its TOML config (`-f/--config`, `--mode` default `monolithic`), runs database migrations, then runs the API server and the periodic garbage collector together.
- 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`bunker cache create` creates a named cache on the server; `bunker use` writes the local Nix configuration so Nix trusts and uses that cache.
- 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`).
- 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.
- 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.
- 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`.
CONCEPTS
CONFIGURATION
| Option | Default | What it does |
|---|---|---|
listen | [::]:8080 | Socket address to listen on |
allowed-hosts | `[]` (all `Host` headers allowed if unconfigured/empty; must be configured for production) | Allowed `Host` headers |
api-endpoint | unset (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.type | local | Storage type: `local` or `s3` |
storage.path | `%storage_path%` (template placeholder) | Local storage directory |
storage.region` / `storage.bucket` / `storage.endpoint | unset (commented in template) | S3 region, bucket, and custom S3-compatible endpoint |
AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY | read from environment if `storage.credentials` is unset | S3 credentials source |
chunking.nar-size-threshold | 65536 | Minimum NAR size to trigger chunking (0 disables, 1 chunks all) |
chunking.min-size | 16384 | Preferred minimum chunk size, in bytes |
chunking.avg-size | 65536 | Preferred average chunk size, in bytes |
chunking.max-size | 262144 | Preferred maximum chunk size, in bytes |
compression.type | zstd | Compression type: `none`, `brotli`, `zstd`, or `xz` |
compression.level | unset (example `8` commented in template) | Compression level |
garbage-collection.interval | 12 hours | GC frequency; zero disables automatic GC (manual: `bunkerd --mode garbage-collector-once`) |
garbage-collection.default-retention-period | zero (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-audiences | unset (commented in template) | If set, received JWTs must match this `iss` / contain one of these `aud` values |
BUNKER_SERVER_TOKEN_ED25519_SECRET_BASE64 | alternative source for `jwt.signing.token-ed25519-secret-base64` | Base64-encoded Ed25519 PEM private key for JWT signing |
BUNKER_SERVER_TOKEN_ED25519_PUBKEY_BASE64 | alternative source for `jwt.signing.token-ed25519-pubkey-base64` | Base64-encoded Ed25519 PEM public key (verify-only) |
`default-server` (client) | unset | Default server to connect to |
`servers.<name>.endpoint` (client) | no default | Server endpoint recorded per named server |
`servers.<name>.token` / `token-file` (client) | no default | Access token inline, or path to a token file |
CONTROLS
| Action | Control |
|---|---|
| Log in to a server | bunker login |
| Configure Nix to use a cache | bunker 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 artifacts | bunker artifact push` / `pull` / `rm |
| Compute a path's closure | `bunker get-closure` (hidden subcommand; full build only) |
| Generate shell completions | bunker 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) client | cargo 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
- 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.
- 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.