In this post I explain how to install NixOS using a temporary file system (tmpfs). This is a precursor to the post I wrote about configuring NixOS for impermanence, and walks through the installation.

Useful References & Notes

The following is summarised from a combination of 2 different blog posts: one detailing how to configure a tmpfs on NixOS and another showing how to harden the NixOS install.

The instructions setup a very simple file system, without a swap partition, just a 512MB boot partition and a root partition on the remaining space. Note: this method is used to create a legacy boot partition, as I use it to create a virtual machine inside of Proxmox. Refer to the linked post above on configuring a tmpfs for UEFI instructions.

Before proceeding you will need a copy of the NixOS Minimal ISO.

Partitioning & Labelling Drives

If unsure first check which drives are available, and confirm which to install on with lsblk. I will be installing on /dev/sda, replace this with the relevant drive if it's different.

# Create legacy boot partition of 512MB
parted /dev/sda -- mklabel msdos
parted /dev/sda -- mkpart primary ext4 1M 512M
parted /dev/sda -- set 1 boot on

# Create root partition on remaining storage
parted /dev/sda -- mkpart primary ext4 512MiB 100%

# Label both partitions
mkfs.ext4 -L boot /dev/sda1
mkfs.ext4 -L nix /dev/sda2

Mount Drive & Create Folders

We need to setup the following folder structure on the drive we prepared before starting a NixOS install.

# Create root mount with tmpfs
mount -t tmpfs none /mnt

# Create folder structure to persist in /nix/persist - srv is optional, used as home directory for services
mkdir -p /mnt/{boot,nix,etc/{nixos,ssh},var/{lib,log},srv}

# Mount relevant partitions to each folder
mount /dev/sda1 /mnt/boot
mount /dev/sda2 /mnt/nix

# Create matching folders in /mnt/nix/persist
mkdir -p /mnt/nix/persist/{etc/{nixos,ssh},var/{lib,log},srv}

# Create temporary bind mounts (later replaced with impermanence - refer to post linked above)
mount -o bind /mnt/nix/persist/etc/nixos /mnt/etc/nixos
mount -o bind /mnt/nix/persist/var/log /mnt/var/log

# Generate a base config
nixos-generate-config --root /mnt

Editing Configuration Files

Before completing the final install we need to make some changes to the generated configuration:

# /mnt/etc/nixos/hardware-configuration.nix

{
  fileSystems."/" = {
    device = "none";
    fsType = "tmpfs";
    # add the line below - limits root storage to 2G maximum
    options = [ "defaults" "size=2G" "mode=755" ];
  };

  # Update both /boot and /nix to use labels rather than UUID
  fileSystems."/boot" = {
    device = "/dev/disk/by-label/boot";
    fsType = "ext4";
  };

  fileSystems."/nix" = {
    device = "/dev/disk/by-label/nix";
    fsType = "ext4";
  };
}

You will also need to edit /mnt/etc/nixos/configuration.nix, how you go about this depends on your needs. Personally I only need to prepare the configuration for deployment via deploy-rs:

# /mnt/etc/nixos/configuration.nix

{ config, pkgs, ... }:

{
  imports = [ ./hardware-configuration.nix ];

  boot.loader.grub.enable = true;
  boot.loader.grub.version = 2;
  boot.loader.grub.device = "/dev/sda";

  # Enable SSH
  services.openssh.enable = true;

  # Configure user with sudo access and SSH key authentication
  users.mutableUsers = false; # prevents any changes to users outside of config file
  users.users.mm = {
    isNormalUser = true;
    extraGroups = [ "wheel" ];
    openssh.authorizedKeys.keys = [
      "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMne13aa88i97xAUqU33dk2FNz+w8OIMGi8LH4BCRFaN"
    ];
  };

  # Persist host ssh keys to enable decrycption of agenix secrets (see below)
  environment.etc."ssh/ssh_host_rsa_key".source
    = "/nix/persist/etc/ssh/ssh_host_rsa_key";
  environment.etc."ssh/ssh_host_rsa_key.pub".source
    = "/nix/persist/etc/ssh/ssh_host_rsa_key.pub";
  environment.etc."ssh/ssh_host_ed25519_key".source
    = "/nix/persist/etc/ssh/ssh_host_ed25519_key";
  environment.etc."ssh/ssh_host_ed25519_key.pub".source
    = "/nix/persist/etc/ssh/ssh_host_ed25519_key.pub";

  # enable nix flakes
  nix.extraOptions = ''
    experimental-features = nix-command flakes
  '';

  # allow for deployment without entering password
  security.sudo.wheelNeedsPassword = false;

  system.stateVersion = "22.11";

}

If you plan on using /etc/nixos/ocnfiguration.nix for configuration, then you will want to ensure your created user also has a password. You may also want to edit the timezone, network settings, hostname and bootloader.

Complete NixOS Install

Finally we run the following to install NixOS:

nixos-install --no-root-passwd

Deploy-rs & Agenix Preparation

This final section is likely irrelevant to most users. I plan on writing about these tools in a future post. Deploy-rs (linked above) allows for deployment of nix flakes to remote machines, and Agenix encrypts any secrets used in the flakes using SSH keys (I've written about it here).

To ensure the host has the correct SSH keys to allow for decryption of secrets be sure to update secrets.nix with the new host key /etc/ssh/ssh_host_ed25516_key.pub. Agenix will then need to be rekeyed to allow any new SSH keys to decrypt secrets:

  • To find out the new host key
ssh-keyscan -t ssh-ed25519 hostname
  • To rekey Agenix secrets
nix run github:ryantm/agenix -- --rekey -i /path/to/original/ssh/key