Setting Up A Private Nix Cache
I recently went through the process of setting up a private Nix binary cache. It was not obvious to me how to go about it at first, so I thought I would document what I did here. There are a few different ways of going about this that might be appropriate in one situation or another, but I’ll just describe the one I ended up using. I need to serve a cache for proprietary code, so I ended up using a cache served via SSH.
Setting up the server
For my cache server I’m using an Amazon EC2 instance with NixOS. It’s pretty easy to create these using the public NixOS 18.03 AMI. I ended up using a t2.medium with 1 TB of storage, but the jury is still out on the ideal tradeoff of specs and cost for our purposes. YMMV.
The NixOS AMI puts the SSH credentials in the root user, so log in like this:
ssh -i /path/to/your/key.pem root@nixcache.example.com
To get your new NixOS machine working as an SSH binary cache there are two things you need to do: generate a signing key and turn on cache serving.
Generate a signing key
You can generate a public/private key pair simply by running the following command:
nix-store --generate-binary-cache-key nixcache.example.com-1 nix-cache-key.sec nix-cache-key.pub
Turn on SSH Nix store serving
NixOS ships out of the box with a config option for enabling this, so it’s pretty easy. Just edit /etc/nixos/configuraton.nix
and add the following lines:
nix = {
extraOptions = ''
secret-key-files = /root/nix-cache-key.sec
'';
sshServe = {
enable = true;
keys = [
"ssh-rsa ..."
"ssh-rsa ..."
...
];
};
};
The extraOptions
section makes the system aware of your signing key. The sshServe
section makes the local Nix store available via the nix-ssh
user. You grant access to the cache by adding your users’ SSH public keys to the keys section.
Setting up the clients
Now you need to add this new cache to your users’ machines so they can get cached binaries instead of building things themselves. The following applies to multi-user Nix setups where there is a Nix daemon that runs as root. This is now the default when you install Nix on macOS. If you are using single-user Nix, then you may not need to do all of the following.
You need to have an SSH public/private key pair for your root user to use the Kadena Nix cache. This makes sense because everything in your local Nix store is world readable, so private cache access needs to be semantically controlled on a per-machine basis, not a per-user basis.
Generating a Root SSH Key
To generate an SSH key for your root user, run the following commands. After the ssh-keygen command hit enter three times to accept the defaults. It is important that you not set a password for this SSH key because the connection will be run automatically and you won’t be able to type a password. You’ll do the rest of the section as the root user, so start by entering a root shell and generating an SSH key pair.
sudo su -
ssh-keygen -b 4096
Next ssh to the cache server. This will tell you that the authenticity of the server can’t be established and ask if you want to continue. Answer ‘yes’. After it connects and prompts you for a password, just hit CTRL-c to cancel.
ssh nixcache.example.com
This has the effect of adding the server to your .ssh/known_hosts
file. If you didn’t do this, SSH would ask you to verify the host authenticity. But SSH will be called automatically by the Nix daemon and it will fail.
Now cat the public key file.
cat ~/.ssh/id_rsa.pub
Copy the contents of this file and send your key to the administrator of the nix cache.
Telling Nix to use the cache
In your $NIX_CONF_DIR/nix.conf
, add your cache to the substituters
line and add the cache's public signing key (generated above with the nix-store command or given to you by your cache administrator) to the trusted-public-keys
line. It might look something like this:
substituters = ssh://nix-ssh@nixcache.example.com https://cache.nixos.org/
trusted-public-keys = nixcache.example.com-1:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa= cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=
Now you need to restart the nix daemon.
On mac:
sudo launchctl stop org.nixos.nix-daemon
sudo launchctl start org.nixos.nix-daemon
On linux:
sudo systemctl restart nix-daemon.service
Populating the Cache
To populate the Nix cache, use the nix-copy-closure
command on any nix store path. For instance, the result
symlink that is created by a nix-build
.
nix-copy-closure -v --gzip --include-outputs --to root@nixcache.example.com <nix-store-path>
After you copy binaries to the cache, you need to sign them with the signing key you created with the nix-store
command above. You can do that by running the following command on the cache server:
nix sign-paths -k nix-cache-key.sec --all
It’s also possible to sign packages on the machines that build them. This would require copying the private signing key around to other servers, so if you’re going to do that you should think carefully about key management.
Maintenance
At some point it is likely that your cache will run low on disk space. When this happens, the nix-collect-garbage
command is your friend for cleaning things up in a gradual way that doesn't suddenly drop long builds on your users.
Comments