Custom NixOS installer ISOs can be created using the nixos-generators project. However, as nixos-generators is built on top of the Nix package manager, it needs to be available. But what if you're using an OS which is not compatible with Nix or don't want to install it on your current system? In this post we'll use the Nix Docker image to resolve this issue.

Prerequisites

The requirements are simple:

  • Have a working Docker installation
  • Have access to the internet during the build process

Steps

Step 1: Create a working directory

Open a terminal, create a new directory and navigate to it.

mkdir \nix
cd \nix

Step 2: Define your customizations

Create a new file in this directory with a .nix-extension, e.g. iso.nix and add the following contents:

{config, pkgs, ...}:

{
  # Add customizations here
}

Customizations to the installer ISO can now be added to this file. Their format is similar to adding these to configuration.nix on a NixOS installation.

In my custom ISO, I want to add an authorized SSH key for the root user; so I can SSH into a system that has been booted with the installer ISO and continue the installation remotely. This can be done by setting the users.users.<name>.openssh.authorizedKeys.keys property by adding the following lines to the created file:

  users.users.root.openssh.authorizedKeys.keys = [
    "ssh-rsa AAAAB...6htA+bHs= ferdy@host"
  ];

You can also add additional packages and have these available using the installation process. To, for example, have access to htop, add the following to your .nix file:

environment.systemPackages = with pkgs; [
    htop
];

Note: these customizations will be applied to the generated installer ISO and the session that is started when booting a system using this ISO and not to the system that will be installed using this ISO.

Step 3: Build the ISO using a Docker container

Now that the configuration file is ready, we can start a container containing the Nix package manager:

docker run --rm -it -v "C:/nixos:/out:rw" -w="/out" nixos/nix

In which:

  • C:/nixos is the path to the current directory; this can be retrieved using the pwd command.
  • /out is the working directory within the container. The volume mount lets us access the .nix file from the previous step within the container, and will also be used to copy the generated ISO out of the Docker container.

nixos-generators can now be installed in the container with:

nix-env -f https://github.com/nix-community/nixos-generators/archive/master.tar.gz -i

When this command is finished, we now have access to the nixos-generators command. We'll use this to build our custom installer ISO:

nixos-generate -f install-iso -c iso.nix -I nixpkgs=channel:nixos-22.05

In which:

  • iso.nix is the name of the configuration created in step 2.
  • 22.05 is the version of NixOS for which the ISO should be build. If -I nixpkgs=channel:nixos-22.05 is ommitted, nixos-unstable will be used.

When nixos-generators has finished building the ISO (which might take a couple of minutes), it outputs the resulting path and filename on the last line of the output:

...
ISO image produced: 427008 sectors
Written to medium : 427008 sectors at LBA 0
Writing to 'stdio:/nix/store/mp856x69p7ssa70j1nlar275ckf1yy89-nixos-22.05.1322.915f5a5b3cc-x86_64-linux.isonixos.iso/iso/nixos-22.05.1322.915f5a5b3cc-x86_64-linux.isonixos.iso' completed successfully.

/nix/store/mp856x69p7ssa70j1nlar275ckf1yy89-nixos-22.05.1322.915f5a5b3cc-x86_64-linux.isonixos.iso/iso/nixos-22.05.1322.915f5a5b3cc-x86_64-linux.isonixos.iso

Note: the filename will differ slightly for the ISO you generated. Use the filename displayed in your terminal, and not the example above.

We can use this to move the ISO to our host system, as the current working directory inside the Docker container has been volume mounted:

mv /nix/store/mp856x69p7ssa70j1nlar275ckf1yy89-nixos-22.05.1322.915f5a5b3cc-x86_64-linux.isonixos.iso/iso/nixos-22.05.1322.915f5a5b3cc-x86_64-linux.isonixos.iso .

You can now check that the generated ISO is available on your host system by using another terminal or file manager to open the directory created in step 1. If all is well, you can close the session into the Docker container using exit. As the --rm flag has been specified, the container itself (and all the packages that have been downloaded) will be removed.

Step 4: Enjoy your custom ISO

You now have a custom NixOS installer ISO that can be used to boot into an installer environment with your custom settings and additional packages applied.

If you want to keep exploring, you can take a look at the nixos-generator's supported formats to generate even more images, including disk images that can be booted directly using a virtual machine!