In a previous post I’ve already shared a way to deploy private git repositories to a NixOS based server. While the old approach is still working I’m using a different approach today. The previously approach requires the private key to be stored on the server. The new approach uses SSH agent forwarding. This way your ssh key never needs to sit on the server.

So this post is basically an update to the previous post to share a simpler way to deploy private git repositories to NixOS hosts.

Example Package

Before we can start, we first need a package to deploy. For this example I picked the nix expression I’m using for this blog:

with import <nixpkgs> {};

stdenv.mkDerivation rec {
    name = "blog";
    src = fetchgitPrivate {
        url = "git@github.com:mpscholten/mpscholten.github.io.git";
        sha256 = "0fy43d0nhbmpf3f8v302r7bhpyd3qk2dyjr2fnvwwdx2825an6cq";
    };
    buildInputs = [ jekyll ];
    buildPhase = "jekyll build";
    installPhase = "cp -R _site \$out";
}

The above nix expression is saved to a file blog.nix locally on my computer (so not on the NixOS host yet). It does nothing more than fetching the source code from the private git repository, doing a jekyll build and copying the resulting _site directory to $out.

The corresponding configuration.nix contains the following lines to run the blog:

services.nginx = {
    enable = true;
    virtualHosts."www.mpscholten.de" = {
        enableACME = true;
        forceSSL = true;
        root = (let blog = import ./blog.nix; in "${blog}");
    };
}

It just adds a vhost to the nginx service and enables letsencrypt.

Enabling SSH Agent Forwarding

As we’re going to use SSH Agent Forwarding for the deployment, we first have to enable it locally. For that we just need to update our local ~/.ssh/config and add a ForwardAgent yes to the host:

This step of course requires that you already use git over ssh locally.

Host digitallyinduced.com
    HostName 46.101.152.239
    User root
    ForwardAgent yes # <--- Add this line

AddKeysToAgent yes # <--- If you're on macOS, you also need to enable this

When we now ssh into the server, we should already be able to just git clone the repository, even though there is no key on the server itself.

The Deployment

To deploy the above package to the NixOS server the blog.nix as well as the configuration.nix are copied to the server. Then a nixos-rebuild switch is started.

By default NixOS will not pick up our SSH Agent Forwarding. To fix that we have to pass the ssh auth socket to nixos-rebuild. We also need to set correct permissions, so that the nix build users can access the socket. Sounds complicated. Luckily Adrien Devresse shared a script to automatically do this on the nix-dev mailing list. Thanks for sharing this Adrien!

The original script is only outputting the new $NIX_PATH, for my uses I changed the script to directly run nixos-rebuild switch. You can find my patched version, which is going to be used below, here: https://gist.github.com/mpscholten/1a12fca4a21fca4fb485148595ffd9b3.

Now we have all the ingridents ready for the actual deployment process. My deploy shell script for the whole thing looks like this:

#!/bin/sh
scp configuration.nix digitallyinduced.com:/etc/nixos/configuration.nix
scp blog.nix digitallyinduced.com:/etc/nixos/blog.nix
scp run_deployment.sh digitallyinduced.com:/root/run_deployment.sh
ssh digitallyinduced.com "chmod +x run_deployment.sh && ./run_deployment.sh";

The usual nixos-rebuild switch is handled by the run_deployment.sh script.

Now by running the above script, NixOS will install the blog package and download the private GitHub repository. That’s it already.

The Result

With the above process we can easily deploy all kinds of private packages to NixOS servers. There’s also never a private key stored on the server.

Thanks for reading :) Follow me on twitter if you’re interested in more of this stuff!