Alright, so after a while, one of the Nix maintainers commented on the issue:
You can nix copy
a derivation and its closure.
I was under the impression that NixOS configurations were built like profiles, without a deriver, but that is not the case.
I think this confusion came from this post of yours:
This is incorrect! --query --deriver
always outputs a derivation, not the output. This is why it’s important to never copy-paste the output of commands without the command you actually ran.
Full instructions
I’ve set up my own NixOS server in the meantime, so now I went through all the steps myself, and this is what worked for me:
Preparation
Make sure that nix --version
returns at least 2.15.1
. Older version might work, but we know for sure that 2.13.3
and 2.13.5
do not!
Building
First, build the system configuration:
$ nixos-rebuild build --flake path/to/flake
building the system configuration...
$ readlink result
/nix/store/r8y8a8gckycx95xdw8wnw1vq5dc13bll-nixos-system-foobar-23.11.20230812.f045184
$ nix-store -q --deriver result
/nix/store/gccqy8z0f78ip7kc4h8s87bb5khg08w0-nixos-system-foobar-23.11.20230812.f045184.drv
Remember the result of readlink result
, that’s what we’re trying to replicate!
Copying to a local binary cache
Note the resulting path of nix-store -q --deriver
is a derivation, and we can nix copy
that quite easily:
$ configDrv=/nix/store/gccqy8z0f78ip7kc4h8s87bb5khg08w0-nixos-system-foobar-23.11.20230812.f045184.drv
$ nix copy $configDrv --to file:///tmp/configCache
Now, don’t be scared, it will look like this command copies like over 10GB of files, but actually, the binary cache we wrote to is pretty small, especially after compressing:
$ cd /tmp
$ du -sh configCache
20M configCache
$ zip -r config.zip configCache
adding: configCache/ (stored 0%)
[ ... ]
$ du -sh config.zip
5.6M config.zip
$ tar -czvf config.tar.gz configCache
configCache/
[...]
$ du -sh config.tar.gz
4.8M config.tar.gz
To confirm the derivation has been copied properly, you can run this command:
$ nix store ls --store file:///tmp/configCache $configDrv
gccqy8z0f78ip7kc4h8s87bb5khg08w0-nixos-system-foobar-23.11.20230812.f045184.drv
Moving and recreating the config on another machine
Copy the file to my other machine (to avoid confusion, I copied it to the same path /tmp/config.tar.gz
), uncompress it, and nix copy
it to the local store:
$ cd /tmp
$ tar -xvzf config.tar.gz
x configCache/
[...]
$ configDrv=/nix/store/gccqy8z0f78ip7kc4h8s87bb5khg08w0-nixos-system-foobar-23.11.20230812.f045184.drv
$ nix copy $configDrv --from file:///tmp/configCache
Now, you can build the configuration like so, and check the result.
$ nix build "${configDrv}^*"
$ readlink result
/nix/store/r8y8a8gckycx95xdw8wnw1vq5dc13bll-nixos-system-foobar-23.11.20230812.f045184
This should be the exact same as when we ran readlink result
after nixos-rebuild
on the original machine.
Activating the config
Finally, activating the configuration is as easy as:
$ ./result/activate
Let me know if this works for you!
Potential caveats
BTW, I found that running the nix copy
command like this:
$ nix copy $(nix-store -q --deriver result) --to file:///tmp/configCache
Did not work. I’m not entirely sure why, maybe I did something wrong, but there doesn’t seem to be an obvious problem with this.