Update 2018: Since this post has been published, I’ve published a newer v2 of this, which is a lot more simple to set up. Check it out here.

In a previous post I’ve already mentioned that this jekyll-powered site is served by NixOS and it’s source code is hosted on a private GitHub repository.

While there’s lots of documentation on how to create a new nix package where the source code is hosted on a public git repository, there’s nearly nothing written about deploying a package hosted on a private repository with NixOS.

Building A Jekyll-Powered Site

Building a jekyll-powered nix package for a public git repository is rather easy. It could look like this:

with import <nixpkgs> {};

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

It does nothing more than fetching the source code from a git repository, doing a jekyll build and copying the resulting _site directory to $out.

We can put this into /etc/nixos/blog.nix and then use it inside the /etc/nixos/configuration.nix by importing it via let blog = import ./blog.nix; in .... Then we can serve it by apache httpd by creating a new virtual host with the document root set to the blog package:

services.httpd.virtualHosts = [
  { hostName = "www.mpscholten.de"; documentRoot = "${blog}" };
]

That’s how we can build and serve a jekyll-powered site via NixOS when the git repository is public available.

Building From A Private GitHub Repository

When the above GitHub repository is private, we have to change the fetchgit of the blog package to fetchgitPrivate:

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 fetchgitPrivate is doing a git checkout via SSH. This requires setting up a SSH configuration describing which SSH key to use when connecting to GitHub.

This configuration could look like:

Host github.com
IdentityFile /etc/ssh/ssh_host_rsa_key
StrictHostKeyChecking=no

It tells SSH to use the RSA key in /etc/ssh/ssh_host_rsa_key when connecting to GitHub. The /etc/ssh/ssh_host_rsa_key is created by NixOS by default, but you could also just generate and use your own key.

The StrictHostKeyChecking=no is to avoid confirming The authenticity of host 'github.com (65.74.177.129)' can't be established. ... Are you sure you want to continue connecting (yes/no)? when connecting to GitHub the first time.

To use the RSA key, it first needs to be granted access to the repository. On GitHub we’ll just add /etc/ssh/ssh_host_rsa_key.pub as a deploy key.

fetchgitPrivate searches for a file path pointing to the above SSH configuration in the NIX_PATH environment variable. Thus we have to write the above configuration into a file and then put the file path into NIX_PATH.

For this the following changes are required in /etc/nixos/configuration.nix:

nix.nixPath = [
  (let
    sshConfigFile =
      pkgs.writeText "ssh_config" ''
        Host github.com
        IdentityFile /etc/ssh/ssh_host_rsa_key
        StrictHostKeyChecking=no
      '';
  in
    "ssh-config-file=${sshConfigFile}"
  )
  # The following lines are just the default values of NIX_PATH
  # We have to keep them to not brick the system
  "nixpkgs=/nix/var/nix/profiles/per-user/root/channels/nixos/nixpkgs"
  "nixos-config=/etc/nixos/configuration.nix"
  "/nix/var/nix/profiles/per-user/root/channels"
];

This introduces a bootstrap problem because on the first nixos-rebuild the NIX_PATH is not containing the ssh-config-file=... and thus the fetchgitPrivate will fail. You can avoid this by first doing a nixos-rebuild with the new nix.nixPath configuration and only after that adding the blog virtual host.

In case your build fails due to permissions issues, the nix build user needs to be given access to the ssh key. You can do this like this: sudo chown nixbld1:nixbld /etc/ssh/ssh_host_rsa_key.

The Result

Now that the RSA key is set up, the fetchgitPrivate should be able to fetch the private GitHub repository and complete the build without issues. If the above steps are not working for you, please let me know.

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