Announcing ncps: A Nix Cache Proxy Server for Faster Builds!

Hey Nix community,

I’m excited to announce ncps, a new proxy server designed to speed up your Nix dependency retrieval and build times, especially in environments with multiple machines.

ncps acts as a local binary cache on your network, fetching store paths from upstream caches (like cache.nixos.org) and storing them locally. This means:

  • Reduced bandwidth usage: Each dependency is pulled only once onto the cache, and then all machines on your network can use it, saving on internet costs and improving network performance.
  • Faster build times: Get your projects built quicker with readily available dependencies.

Here’s what makes ncps stand out:

  • Easy setup: Get it running with just a few configuration flags.
  • Multiple upstream caches: Configure multiple sources for redundancy and flexibility.
  • Secure caching: ncps signs cached paths with its own key, ensuring integrity.
  • Cache size management: Prevent your cache from growing indefinitely with configurable maximum size and automated cleanup.
  • Zstandard compression support: Specifically designed for use with Harmonia, ncps efficiently stores and serves NAR files compressed with zstd as received during HTTP transport, without any decompression overhead. This results in faster storage and retrieval of dependencies.
  • OpenTelemetry support: Integrate with OpenTelemetry for centralized logging, metrics, and tracing.

Ready to try it out?

Head over to the GitHub repository for installation instructions, documentation, and examples: https://github.com/kalbasit/ncps

I’d love to hear your feedback and any suggestions you might have. Feel free to open issues or submit pull requests on GitHub.

Give ncps a try and let’s make Nix builds fly! :rocket:

p.s:

35 Likes

Does nix.settings.substituters work well with unreachable caches, like when you are not home and your cache is using a lan ip?

1 Like

no, nix does not handle this well; you need to put things like this in trusted-substituters and specify them on the command line when you want to use them.

One key hope for a proxy like this is that it might help handle the errors more gracefully, as long as the proxy itself is reachable (which perhaps means local)

4 Likes

I was thinking of adding a feature to return priority based on client’s IP address: Less than 30 for local clients and >100 for remote; But I wanted to wait to gather more use-cases before I commit to adding more complexity.

2 Likes

Ah, this is sick! Great work–hopefully once this hits nixpkgs it’ll end up in a lot of folks’ toolbelts!

1 Like

Are they any plans to used content defined chunks to store the nars on disks to save space?

2 Likes

This looks really interesting, as this duplication of downloads is something I’m definitely hitting!

However I was hoping to use a binary cache also for anything I end up compiling, when it’s not already in the official cache.

Is there a way I could achieve that automatically, as well as ncps primary benefits?
If not, is some kind of ability to automatically push locally built packages to ncps a realistic possibility in future?

The readme suggests it supports PUT with the appropriate command line option - not sure if. Nix supports uploads to http stores though?

1 Like

Ah, yes, it seems so: Documentation on how the http(s) binary cache API works? - #2 by domenkozar

Does nix.settings.substituters work well with unreachable caches, […]

No, and here’s a PR that aimed to fix that: Allow missing binary caches by default by arcuru · Pull Request #7188 · NixOS/nix · GitHub

4 Likes

Nice, this is what I was looking for a few years ago, when I needed a package proxy and then used nginx as a reverse proxy!

2 Likes

Is there any nix proposal that would allow us to “set a cache proxy” that would always be used when fetching store paths and would allow us to cache store paths from every nix caches we use?

In other words, with ncps, we need to specify the upstream caches in advance. Wouldn’t it be nice to just have a “proxy” that would cache everything (without having to use a MITM proxy)?

Secure caching: ncps signs cached paths with its own key, ensuring integrity.

Does it replace Hydra’s signature, or add another one? Also, is it doing the verifying, or is Nix?

ncps pulls from upstream cache, and verifies signature. Once verified, it adds its signature to the existing ones.

Here’s an example of the hello package pulled directly from cache.nixos.org and then from my ncps on my network:

❯ curl https://cache.nixos.org/1q8w6gl1ll0mwfkqc3c2yx005s6wwfrl.narinfo
StorePath: /nix/store/1q8w6gl1ll0mwfkqc3c2yx005s6wwfrl-hello-2.12.1
URL: nar/1dglqjx5wm3sdq0ggngcyh4gpcwykngkxps0a8v4v1f1f2lzdwd1.nar.xz
Compression: xz
FileHash: sha256:1dglqjx5wm3sdq0ggngcyh4gpcwykngkxps0a8v4v1f1f2lzdwd1
FileSize: 50364
NarHash: sha256:1bn7c3bf5z32cdgylhbp9nzhh6ydib5ngsm6mdhsvf233g0nh1ac
NarSize: 226560
References: 1q8w6gl1ll0mwfkqc3c2yx005s6wwfrl-hello-2.12.1 wn7v2vhyyyi6clcyn0s9ixvl7d4d87ic-glibc-2.40-36
Deriver: k1rx7pnkdlzfscv6jqzwl4x89kcknfy1-hello-2.12.1.drv
Sig: cache.nixos.org-1:qt4d4o04/cklIMANVntoLYHh36t1j+y/35qWoK2GeeeEeYU5RElnV/gpXrc5jgx4p2MQ38TasPhHg8rN6O+5Dw==

❯ curl https://nix-cache.cluster.ifcsn0.nasreddine.com/1q8w6gl1ll0mwfkqc3c2yx005s6wwfrl.narinfo
StorePath: /nix/store/1q8w6gl1ll0mwfkqc3c2yx005s6wwfrl-hello-2.12.1
URL: nar/1dglqjx5wm3sdq0ggngcyh4gpcwykngkxps0a8v4v1f1f2lzdwd1.nar.xz
Compression: xz
FileHash: sha256:1dglqjx5wm3sdq0ggngcyh4gpcwykngkxps0a8v4v1f1f2lzdwd1
FileSize: 50364
NarHash: sha256:1bn7c3bf5z32cdgylhbp9nzhh6ydib5ngsm6mdhsvf233g0nh1ac
NarSize: 226560
References: 1q8w6gl1ll0mwfkqc3c2yx005s6wwfrl-hello-2.12.1 wn7v2vhyyyi6clcyn0s9ixvl7d4d87ic-glibc-2.40-36
Deriver: k1rx7pnkdlzfscv6jqzwl4x89kcknfy1-hello-2.12.1.drv
Sig: cache.nixos.org-1:qt4d4o04/cklIMANVntoLYHh36t1j+y/35qWoK2GeeeEeYU5RElnV/gpXrc5jgx4p2MQ38TasPhHg8rN6O+5Dw==
Sig: nix-cache.cluster.nasreddine.com:vzh0W8CrV0waXOQU7Ai3klxsvsO7vG5CEoi2u4QtN0h0h30MoMbt+cW5R7N5HblUa2ChIz+/xMflrsZiJOriDQ==
3 Likes

Yes, it does. I use it all the time. I build my servers locally, send them to my nix cache and when I apply each server it goes pretty fast since it pulls from the cache over my 10G network; My aim is to minimize downtime on my Kubernetes cluster.

Example of how I use it:

nix copy --to "https://nix-cache.cluster.ifcsn0.nasreddine.com" $(readlink -f result)
2 Likes

That’s exactly why I added the PUT functionality gated with the --cache-allow-put-verb which allows you to push directly to the cache. Example of how I use it:

nix copy --to "https://nix-cache.cluster.ifcsn0.nasreddine.com" $(readlink -f result)

Be aware, that PUT is unauthenticated currently so if your cache is publicly accessible, it will allow anyone to push to it.

2 Likes

Not at this time since that will complicate garbage collection (implemented as LRU). I would be willing to review pull requests for it. Please consider opening an issue on ncps to allow people to vote on it, with enough votes, I’d consider spending the time on it.

2 Likes