cupboard is a Nix binary cache that you run on your own Cloudflare account.
- It runs on Cloudflare Workers and R2, on the free tier. There are no servers to run, and a small deployment costs nothing.
- One deployment hosts many tenants. Each tenant has its own caches, signing key, credentials and retention settings, so one deployment can serve every team in an organisation, and no tenant can see another's data.
- A tenant can have as many caches as it needs, public or private. Private reads need authorised credentials. Each cache can have its own static read credential.
- CI publishes without a stored push credential. A GitHub Actions job signs in with the OIDC token that GitHub already gives it. A job can also use OIDC for private reads when its trust rules permit content reads. Static read credentials remain available. See Private reads in CI. A trust rule on your tenant says which repository, branch or pull request to accept, and what that job may do. The signing key never leaves the server.
- Store paths are kept by named retention roots, which can expire, and a cache can also keep paths for a grace period. Garbage collection deletes every path that no root or grace period keeps, so a cache that CI fills every day doesn't grow forever.
- The reusable workflow gives every pull request its own cache, reuses those
builds when the change reaches
main, and signs build provenance for what it builds. - It's a standard Nix binary cache. Any Nix that can decompress zstd can substitute from it, with nothing extra installed.
Why cupboard compares it with Cachix, Attic and a plain bucket, and lists what it can't do yet.
-
Install the CLI:
nix profile install github:underwhelmingperformance/cupboard/vX.Y.Z
Replace
vX.Y.Zwith a published release tag, and use that same tag for the reusable workflow below. There are also prebuilt archives on the releases page. Installing the CLI covers both, including how to verify a release. -
In the Cloudflare dashboard, enable R2, create a bucket called
cupboard-blobs, and create an R2 API token that can read and write it. Then deploy:cupboard init --instance-name cupboard
This walkthrough uses browser sign-in and an existing R2 key. With a Cloudflare API token that can manage account tokens,
initcan create the bucket and a key scoped to writes in that bucket. See R2 credentials for that alternative.initsigns you in to Cloudflare through your browser, creates the Workers and their storage, and creates your first tenant. The firstinitfrom a terminal also makes you the deployment's admin, after you confirm the identity that it shows. Run it from a terminal: a firstinitwithout one leaves the deployment without an admin.initfinishes by printing the tenant's read credential and the lines to add tonix.conf. Deploying cupboard explains each step and each choice.A later
initupgrades the deployment and needs the admin's token. At a terminal it signs you in if needed. From CI, it needs a control-plane trust rule, as Updating from CI describes. -
Sign in to the new tenant, then push something.
initsaves a session for the deployment, and pushing needs a session for the tenant:cupboard login https://cupboard.example.workers.dev/t/acme cupboard push https://cupboard.example.workers.dev/t/acme ./result
-
Add the lines that
initprinted tonix.conf. If the cache is private, also save the netrc line thatinitprinted, which contains the read credential, in a netrc file outside the Nix store. Using a cache shows where the lines go on NixOS, nix-darwin, Home Manager and plain Nix installs, and Private caches shows how to give Nix the credential.
First, add the trust rules and reuse view for the repository to your tenant:
cupboard github setup https://cupboard.example.workers.dev/t/acme \
--repo acme/app \
--workflow-ref 'underwhelmingperformance/cupboard/.github/workflows/cupboard-flake-publish.yml@refs/tags/v*'The workflow builds the targets that the flake lists in its cupboardOutputs
output, so define that first; the
quickstart shows how.
Then add a workflow to the repository that calls cupboard's. This is the core of
it:
on:
pull_request:
types: [opened, synchronize, reopened, closed]
push:
branches: [main]
jobs:
publish:
permissions:
attestations: write
contents: read
id-token: write
uses: underwhelmingperformance/cupboard/.github/workflows/cupboard-flake-publish.yml@vX.Y.Z
with:
url: https://cupboard.example.workers.dev/t/acme
preset: pull-request-and-branch
trusted-public-key: cupboard-acme-1:...Every pull request now builds the flake's outputs into its own cache, and every
push to main publishes to the default cache, reusing the pull request's builds
where they match. Copy the complete workflow file from
Add the workflow rather than this
excerpt: it also skips pull requests from forks, which the preset refuses, and
cancels a pull request's previous run when a new commit arrives.
The control plane is one Worker with a D1 database. Each tenant is a Durable Object, which keeps the tenant's narinfos, roots, keys and trust rules in its own SQLite database. NARs and attestations are in R2, stored once however many tenants publish them. R2 doesn't charge for egress, so serving builds costs storage and requests, not bandwidth. An hourly cron job queues garbage collection and key retirement for up to 100 due tenants. An active tenant becomes due when it has work to do or six hours have passed since its maintenance eligibility was last reconciled. Queue delivery, other due tenants and maintenance failures can delay completion. Architecture goes through it in detail.
cupboard is pre-1.0. Releases are numbered v0.0.x, and a release can change
the format of stored data. When one does, upgrading runs a staged migration, and
once tenants have migrated you can't roll back.
Why cupboard compares it with the alternatives and
lists the things it can't do yet.
The documentation index lists every page. The pages to start with are:
- Using a cache, if someone has set up a cache for you.
- Administering a tenant, if you manage a tenant's caches, keys and access.
- Publishing from GitHub Actions.
- Deploying cupboard, if you run the deployment.
- Contributing.
To report a vulnerability, see the security policy. The security model describes who cupboard trusts and how tenants are kept apart.
cupboard is licensed under the GNU Affero General Public License v3.0 or later.