From b2283ba3288316c0c0ea38d7a77a285443dd7999 Mon Sep 17 00:00:00 2001 From: moons Date: Sat, 18 Jul 2026 20:09:04 +0900 Subject: [PATCH] nix cache --- .github/workflows/publish-nixcache.yml | 64 ++++++++++++++++++++++ README.md | 21 +++++++ flake.lock | 21 +++++++ flake.nix | 6 ++ modules/features/services/default.nix | 1 + modules/features/services/nixcache-oci.nix | 17 ++++++ modules/system/default.nix | 3 + modules/system/nixcache-oci.nix | 27 +++++++++ profiles/interfaces/cli-minimal.nix | 1 + 9 files changed, 161 insertions(+) create mode 100644 .github/workflows/publish-nixcache.yml create mode 100644 modules/features/services/nixcache-oci.nix create mode 100644 modules/system/nixcache-oci.nix diff --git a/.github/workflows/publish-nixcache.yml b/.github/workflows/publish-nixcache.yml new file mode 100644 index 0000000..232b520 --- /dev/null +++ b/.github/workflows/publish-nixcache.yml @@ -0,0 +1,64 @@ +name: Publish Nix cache +on: + push: + branches: + - main + workflow_dispatch: +permissions: + contents: write + packages: write +concurrency: + group: publish-nixcache-${{ github.ref }} + cancel-in-progress: false +jobs: + publish: + name: Build and publish uncached paths + runs-on: ubuntu-latest + timeout-minutes: 180 + steps: + - name: Checkout repository + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: true + - name: Install Nix + uses: cachix/install-nix-action@630ae543ea3a38a9a4166f03376c02c50f408342 # v31.11.0 + with: + extra_nix_config: | + experimental-features = nix-command flakes + accept-flake-config = true + access-tokens = github.com=${{ github.token }} + - name: Configure cache signing + env: + NIX_SIGNING_KEY: ${{ secrets.NIX_SIGNING_KEY }} + run: | + set -euo pipefail + test -n "$NIX_SIGNING_KEY" || { + echo "NIX_SIGNING_KEY is required; refusing to publish unsigned cache paths." >&2 + exit 1 + } + signing_key="$RUNNER_TEMP/nixcache-signing-key" + umask 077 + printf '%s' "$NIX_SIGNING_KEY" > "$signing_key" + nix key convert-secret-to-public < "$signing_key" > nixcache-public-key.txt + echo "NIXCACHE_SIGNING_KEY_FILE=$signing_key" >> "$GITHUB_ENV" + - name: Commit cache public key + run: | + set -euo pipefail + if git diff --quiet -- nixcache-public-key.txt; then + exit 0 + fi + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add nixcache-public-key.txt + git commit -m "chore: publish Nix cache signing key" + git push + - name: Build and publish uncached store paths + env: + GITHUB_TOKEN: ${{ github.token }} + NIXCACHE_REPO: ${{ github.repository }} + NIXCACHE_CONFIG_DIR: . + run: | + set -euo pipefail + nixcache_source="$(nix flake archive --json --no-write-lock-file github:cmspam/nixcache-oci/fb6006b5575da494dbbfc582e841d976ec06be6e | jq -r .path)" + source "$nixcache_source/lib/cache-builder.sh" + full_pipeline diff --git a/README.md b/README.md index bf8ae74..e0bf7fb 100644 --- a/README.md +++ b/README.md @@ -179,6 +179,27 @@ sudo nixos-rebuild switch --flake .# # Apply config sudo nixos-rebuild build --flake .# # Build without applying ``` +## Nix Binary Cache + +All normal hosts run `nixcache-oci` as a local proxy for +`ghcr.io/moons-14/dotfiles/nix-cache`. The `Publish Nix cache` workflow builds +the flake on pushes to `main` and uploads only store paths that were built by +the runner rather than substituted from an existing cache. Nix still uses the +official cache and configured Cachix caches for all other paths. + +The cache must remain public and signed: + +1. Generate a signing key outside this repository and save its contents as the + `NIX_SIGNING_KEY` GitHub Actions secret. +2. Run the `Publish Nix cache` workflow. It commits `nixcache-public-key.txt`, + which clients trust on their next configuration rebuild. +3. In GitHub Packages, make the `nix-cache` container package public. + +```sh +nix key generate-secret > /tmp/nixcache-signing-key +# Copy the contents into the NIX_SIGNING_KEY GitHub Actions secret, then delete the local file. +``` + ## Inspired - [Zaney/zaneyos](https://gitlab.com/Zaney/zaneyos) diff --git a/flake.lock b/flake.lock index 71534c7..6ff883b 100644 --- a/flake.lock +++ b/flake.lock @@ -634,6 +634,26 @@ "type": "github" } }, + "nixcache-oci": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1784221638, + "narHash": "sha256-dBzaw2Itm5Rg7YTvlI+LU6d2yTZXlpbVLARO2RmTvHw=", + "owner": "cmspam", + "repo": "nixcache-oci", + "rev": "fb6006b5575da494dbbfc582e841d976ec06be6e", + "type": "github" + }, + "original": { + "owner": "cmspam", + "repo": "nixcache-oci", + "type": "github" + } + }, "nixos-hardware": { "inputs": { "nixpkgs": "nixpkgs_4" @@ -976,6 +996,7 @@ "niri-flake": "niri-flake", "nix-hazkey": "nix-hazkey", "nix-index-database": "nix-index-database", + "nixcache-oci": "nixcache-oci", "nixos-hardware": "nixos-hardware", "nixos-wsl": "nixos-wsl", "nixpkgs": "nixpkgs_6", diff --git a/flake.nix b/flake.nix index 98448b1..ed63f8d 100644 --- a/flake.nix +++ b/flake.nix @@ -92,6 +92,12 @@ inputs.nixpkgs.follows = "nixpkgs"; }; + # Binary cache + nixcache-oci = { + url = "github:cmspam/nixcache-oci"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + # Systems systems.url = "github:nix-systems/default-linux"; diff --git a/modules/features/services/default.nix b/modules/features/services/default.nix index 7b5a6f5..1c4970d 100644 --- a/modules/features/services/default.nix +++ b/modules/features/services/default.nix @@ -2,6 +2,7 @@ imports = [ ./container.nix ./kde.nix + ./nixcache-oci.nix ./quem-guest.nix ]; } diff --git a/modules/features/services/nixcache-oci.nix b/modules/features/services/nixcache-oci.nix new file mode 100644 index 0000000..7b7a3ce --- /dev/null +++ b/modules/features/services/nixcache-oci.nix @@ -0,0 +1,17 @@ +{ + lib, + config, + ... +}: +let + cfg = config.my.features.services.nixcacheOci; +in +{ + options.my.features.services.nixcacheOci = { + enable = lib.mkEnableOption "Nix binary cache backed by public GHCR"; + }; + + config = lib.mkIf cfg.enable { + my.system.nixcacheOci.enable = true; + }; +} diff --git a/modules/system/default.nix b/modules/system/default.nix index 35af27a..a8dc98d 100644 --- a/modules/system/default.nix +++ b/modules/system/default.nix @@ -1,3 +1,4 @@ +{ inputs, ... }: { imports = [ ./audio.nix @@ -11,6 +12,7 @@ ./locale.nix ./network ./nix.nix + ./nixcache-oci.nix ./power.nix ./quem.nix ./secure-boot.nix @@ -18,5 +20,6 @@ ./user ./version.nix ./secret.nix + inputs.nixcache-oci.nixosModules.default ]; } diff --git a/modules/system/nixcache-oci.nix b/modules/system/nixcache-oci.nix new file mode 100644 index 0000000..0cdead9 --- /dev/null +++ b/modules/system/nixcache-oci.nix @@ -0,0 +1,27 @@ +{ + lib, + config, + ... +}: +let + cfg = config.my.system.nixcacheOci; + publicKeyFile = ../../nixcache-public-key.txt; + publicKey = + if builtins.pathExists publicKeyFile then + lib.strings.trim (builtins.readFile publicKeyFile) + else + ""; +in +{ + options.my.system.nixcacheOci = { + enable = lib.mkEnableOption "Nix binary cache backed by the public GitHub Container Registry"; + }; + + config = lib.mkIf cfg.enable { + services.nixcache-proxy = { + enable = true; + repo = "moons-14/dotfiles"; + inherit publicKey; + }; + }; +} diff --git a/profiles/interfaces/cli-minimal.nix b/profiles/interfaces/cli-minimal.nix index e3f2f38..894cbf3 100644 --- a/profiles/interfaces/cli-minimal.nix +++ b/profiles/interfaces/cli-minimal.nix @@ -5,5 +5,6 @@ shell.enable = true; }; identity.sshDefaultKey.enable = true; + services.nixcacheOci.enable = true; }; }