How to 1312 Blogs, part 1: provisioning a dedicated server with NixOS

Documenting here how the server supporting 1312 Blogs (and a few other blog sites) was created.

So I'm using nixos-anywhere to provision NixOS to my hosted dedicated servers. nixos-anywhere purpose is to transform any linux machine with ssh access into a NixOS machine.

For this nixos-anywhere only need a description of the disk layout you want to end-up with. More precisely, it uses disko to support declarative disk partitioning.

My declarative partitioning look like this:

disko.nix

{
  disko.devices = {
    disk = {
      sda = {
        type = "disk";
        device = "/dev/sda";
        content = {
          type = "gpt";
          partitions = {
            BOOT = {
              size = "1M";
              type = "EF02"; # for grub MBR
            };
            ESP = {
              size = "1000M";
              type = "EF00";
              content = {
                type = "filesystem";
                format = "ext4";
                mountpoint = "/boot";
              };
            };
            luks = {
              size = "100%";
              content = {
                type = "luks";
                name = "crypted";
                askPassword = true;
                content = {
                  type = "filesystem";
                  format = "ext4";
                  mountpoint = "/";
                };
              };
            };
          };
        };
      };
    };
  };
}

So only 2 partitions, /boot and an encrypted /. Now I don't have physical access to the machine, so to decrypt the root partition we will bundle an ssh server into the initrd, as explained in this blog post by Carlos Vaz or this one by Matthias Totschnig:

flake.nix

{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11";
    disko = {
      url = "github:nix-community/disko";
      inputs.nixpkgs.follows = "nixpkgs";
    };
  };
  outputs = { nixpkgs, disko, ... }: {
    nixosConfigurations = {
      server = nixpkgs.lib.nixosSystem rec {
        system = "x86_64-linux";
        modules = [
          disko.nixosModules.disko
          ./disko.nix
          ./configuration.nix
          {
            boot.initrd.network = {
              # Make sure you have added the kernel module for your network driver to `boot.initrd.availableKernelModules`
              enable = true;
              ssh = {
                enable = true;
                # To prevent ssh clients from freaking out because a different host key is used,
                # a different port for ssh is useful (assuming the same host has also a regular sshd running)
                port = 2222;
                hostKeys = [ "/etc/ssh/initrd-ssh-host-key" ];
                # public ssh key used for login
                authorizedKeys = [
                  "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPEvEVBYFc/u2vRUaiQgV/t4aA6tqhlvNj/OrUkHa1Pz"
                ];
              };
              # ask for secret key on login
              postCommands = ''
                cat <<'EOF' > /root/.profile
                echo "Enter encrypted volume passphrase"
                read -s pass
                echo "$pass" > /crypt-ramfs/passphrase && exit
                EOF
              '';
            };
          }
        ];
      };
    };
  };
}

To go one setup further, one could use Tailscale ssh instead.

Then we run nixos-anywhere with the necessary secrets, as per documentation:

temp=$(mktemp -d)
cleanup() {
  rm -rf "$temp"
}
trap cleanup EXIT
install -d -m755 "$temp/etc/ssh"
ssh-keygen -t ed25519 -N "" -f "$temp/etc/ssh/initrd-ssh-host-key"
chmod 600 "$temp/etc/ssh/initrd-ssh-host-key"

read -s my_disk_encryption_password

nix run github:nix-community/nixos-anywhere -- \
  --extra-files "$temp" \
  --disk-encryption-keys /tmp/luks.key <(echo $my_disk_encryption_password) \
  --flake '.#server' ubuntu@nsxxxxx.ip-xx-xx-xx-xx.eu

Note: beware that this method does not prevent an attacker with physical access to intercept you password by forcing the machine to reboot into a crafted shell under attacker control. To prevent this you would need to setup UEFI Secure Boot with lanzaboote (that means having access to the machine BIOS, which must have reliable TPM support).

disclaimer: I am not a professional security expert / cryptographer.

Still,

All Crypted-disks Are Beautiful

#FullDiskEncryption #NixOS