Nix Flakes and Private Repositories

The basic problem I have is that I’m trying to use private repositories as dependencies in Nix Flakes.

Specifically, I’m trying to build an EC2 webserver using static web files compiled into a Nix derivation with Flakes, that then gets used in a Nix Flakes NixOS definition. While this builds fine on my computer, because I’ve set SSH keys for GitHub and am using a SSH link, I’m not sure how best to successfully deploy it.

A few ideas I’ve had:

  • make the repository public (not ideal, but possible)
  • hard-code ssh keys into the nixos config (no, insecure)
  • Set up a private flake registry (complex, but possibly workable)
  • Write ansible/ssh scripts to deploy NixOS and create SSH keys (probably easiest, but a bit of work and additional layer of complexity)

Any recommendations?

Edit: It’s kinda a hack, but I ended up just building the web site locally and pushing it and the NixOS config via scp. Not ideal though, so I’m still definitely looking into these recommendations


What about sops-nix, or some other mechanism for deploying state that’s possibly encrypted locally? Probably most deployment systems for nix like NixOps, morph, krops have use some mechanism for deploying secrets that don’t land in the nix store. Dysnomia would be only for deploying any state. You can also simply rsync secrets to some directory on the server and encrypt them locally e.g. with git-crypt next to your nixos config. At the server, you certainly need the unencrypted key somewhere to fetch the repo.

Edit: Here’s an interesting thread: Comparison of different key/secret managing schemes

1 Like

Can you build the thing locally and then push it to the remote machine with nix-copy-closure? I mean the first sentence of Eelco’s Phd Thesis is

This thesis is about getting computer programs from one machine to another—and having
them still work when they get there.

More generally speaking maybe your EC2 server does not even need access to the private git repo but only the machine building the website.

1 Like

@jorsn I suppose I didn’t do enough due diligence in my research. NixOps I had heard wasn’t well supported (ironic then that I’m using flakes), and hadn’t heard of the rest. I can definitely try looking into some of those.

@lucc Did not know nix-copy-closure was a thing either. Given how I’m doing things currently (originally was going to be ansible, then realized everything I wanted was doable in a bash script), that’s probably the easiest to implement

NixOps also builds your stuff locally and copies it (probably with nix-copy-closure).

Building locally (which NixOps does and probably also deploy-rs) vs building remotely (which most other systems seem to do) is one main difference between deploying solutions. Did you know these two pages:

They list some different solutions.

NixOps can even set up your AWS resources.

I use flakes with private repos all the time, use ssh+git like so

$ nix build ssh+git://

@jorsn NixOps is probably the answer, but I’m still not entirely sure. I can definitely build it locally but cannot remotely (the target has 1GiB of RAM, not enough for a NodeJS app), and can push the built files themselves, but trying to use nix copy (using the nix3 command style), the closure copied never has a matching NAR hash as to what the NixOS image is expecting. NixOps or if the closures were content-addressed would probably fix it, but for now I’m undecided what to do.

I might be able to write it as a NixOS Module too now that I’ve done that with my nix-home and dotfiles repos, but I don’t see how that would help.

@siraben Yeah, you can use SSH to get it there, but I’d have to manually log into GitHub on the server or somehow set up deploy keys first

1 Like

Maybe this changed, but I’ve found that it needs to be git+ssh, not ssh+git.

In fact, I think this example would need to become nix build git+ssh://

If anyone stumbles across this, the final flake URI that works is:



  • The git has to come before the ssh (i.e. git+ssh and not ssh+git)
  • and the ${username} need to be separated by a / and not a :

I’m only mentioning this because none of the comments so far had the complete correct invocation.


Ah, thanks. Not sure how I managed to get that wrong given my preceding comment.