Provide flake nixpkgs input from a binary cache?

Hello all.

Due to a weird setup (proxy restrictions), I have some lab machines with nix daemon:

  • with NO access to github (ie no access to fetch the flake input like github:nixos/nixpkgs?rev=…)
  • with access to a local binary cache localy managed.

Some other online machines have accesses to fetch (from github) and build the stuff, then push the built packages on the localy managed binary cache. I want then the offline lab machines to be able to build packages only by fetching necessary stuff from the local binary cache.

The main issue with this approach is: how can I make offline nix fetch the flake input from the binary cache ?

When I run the below command,

nix flake metadata “github:nixos/nixpkgs?rev=xxx”

I quickly get the input path /nix/store/hash-source. Is the mapping “flake.input” → “/nix/store/hash-source” stored somewhere ? I don’t see it in flake.lock ?

I might then need to make the /nix/store/hash-source available on offline machine. I have found the “nix flake archive” or “nix copy” which produces NARs, and I could then push these NARs onto the local binary cache. But then, how would the lab machines figure out that to get the “github:nixos/nixpkgs?rev=xxx” input, it should download “/nix/store/hash-source” from the binary cache ?

I hope these questions and this setup are understandable; don’t hesitate to say it if this approach is absolute non-sense or if there are completely different approaches.

If you’re still there, thanks for your time reading ^^

Can you reach channels.nixos.org from those machines?

1 Like

Hey

The channels are neither reachable… but you made me realise I should provide nixpkgs zip tarballs instead of attempting to go via NARs. This approach seems to work.

@waffle8946 Thanks for your answer, and more generally thanks a lot for sharing your knowledge and expert advises on all the discussions in this forum, that helps a lot.

1 Like

Generally, if those inputs are in the lock file then internal call-flake.nix magic will invoke fetchTree with a hidden (poorly, see below) non-user-facing flag that will make it try to substitute. The quality of the implementation for substituting flake inputs various depending on the nix version you are using. Recent versions like 2.32 should substitute stuff from the lock file correctly. The code for that is a mess somewhat, so it’s hard to tell what works and what doesn’t.

If you want to be able to use nixpkgs tarballs from a substituter in an ad-hoc manner there’s also the builtins.fetchClosure gated behind fetch-closure experimental feature. Also starting with 2.32 (or <= 2.24) fetchurl, fetchTarball do substitute when provided the NAR hash.


Below is a hilarious discovery that I stumbled upon while spelunking for possible answers to your question. This works as of 2.30…2.32 and possibly some versions below as well

Also if you are not afraid of exploiting the careless implementation of flakes :clown_face: (yay for stringly typed code) you can do the following so that nix flake metadata nixpkgs-test will use substituters for ad-hoc commands like nix build nixpkgs-test#hello.

Put this or something like this (adapted to your use case) in ~/.config/nix/registry.json (that’s the user flake registry). Alternatively you could configure flake-registry = /path/to/file/with/this. I presume you are already disabling the global registry since it would try to reach out to the internet to fetch it from channels.nixos.org.

{
  "flakes": [
    {
      "from": {
        "id": "nixpkgs-test",
        "type": "indirect"
      },
      "to": {
        "__final": true,
        "owner": "NixOS",
        "repo": "nixpkgs",
        "type": "github",
        "rev": "9a7b80b6f82a71ea04270d7ba11b48855681c4b0",
        "narHash": "sha256-82L+EJU+40+FIdeG4gmUlOF1jeSwlf2AwMarrpdHF6o="
      }
    }
  ],
  "version": 2
}

Then you can do whatever you want with this indirect flake reference and fetching it will reach out to the substituter:

nix flake archive "nixpkgs-test" --to file:///tmp/some-store
nix flake prefetch nixpkgs-test --substituters "file:///tmp/some-store" --store "/tmp/some-store2"

The exploiting the implementation part is manually specifying __final. That is the (poorly) hidden knob that makes nix try to substitute flakes. Funnily enough, if you try to do the same thing with fetchTree you’ll get an error:

builtins.fetchTree { type = "github"; owner = "nixos"; repo = "nixpkgs"; rev = "9a7b80b6f82a71ea04270d7ba11b48855681c4b0"; narHash = "sha256-82L+EJU+40+FIdeG4gmUlOF1jeSwlf2AwMarrpdHF6o="; __final = true; }
input 'github:nixos/nixpkgs/9a7b80b6f82a71ea04270d7ba11b48855681c4b0?narHash=sha256-82L%2BEJU%2B40%2BFIdeG4gmUlOF1jeSwlf2AwMarrpdHF6o%3D' is not allowed to use the '__final' attribute

The flake registry is exempt from this check (for now :joy:).

Thanks ! I might no go following your tricky solution, assuming that this trick might not work forever… But anyway thanks for the look and the answer