Test-Driving a NixOS VM Using Libvirt

NixOS has a lot of really cool ideas, but unfortunately installing on a VM is still tricky. This guide is designed as a “just get me something working, please!” way to get a headless NixOS install up and running in a libvirt VM.

Prerequisites

You will need to have libvirt and virt-install on your system.

On Ubuntu:

1sudo apt update
2sudo apt install qemu-kvm libvirt-daemon-system virtinst

On Redhat:

1sudo yum install kvm virt-manager libvirt libvirt-python python-virtinst

You’ll also need the NixOS minimal ISO image

Launching the VM

Use the following as an example for launching your vm, picking a decent place to create your qcow2 disk image (you will be installing to this) so that you can find it later:

1virt-install --name=nixos \
2--memory=8196 \
3--vcpus=2 \
4--disk /path/to/my-nixos-disk-image.qcow2,device=disk,bus=virtio,size=16 \
5--cdrom=/path/to/latest-nixos-minimal-x86_64-linux.iso \
6--os-type=generic  \
7--boot=uefi \
8--nographics \
9--console pty,target_type=virtio

This launches a UEFI-enabled (--boot=uefi) headless (--nographics) VM named “nixos” (--name=nixos) with 8 GB of RAM (--memory=8192), 2 CPUs (--vcpus=2), and a disk image with 16GB of space (size=16). It also connects to the guest’s console (--console pty,target_type=virtio).

Note: The --cdrom entry sets the ISO image to boot from once. After rebooting, it will boot from your qcow2 image instead.

After launching the VM, it will sit here for awhile, looking like it’s stuck:

1Starting install...
2Connected to domain nixos
3Escape character is ^]

Just be patient; it should boot within a couple of minutes:

 1<<< Welcome to NixOS 21.05.1970.11c662074e2 (x86_64) - hvc0 >>>
 2The "nixos" and "root" accounts have empty passwords.
 3
 4An ssh daemon is running. You then must set a password
 5for either "root" or "nixos" with `passwd` or add an ssh key
 6to /home/nixos/.ssh/authorized_keys be able to login.
 7
 8
 9Run 'nixos-help' for the NixOS manual.
10
11nixos login: nixos (automatic login)
12
13
14[nixos@nixos:~]$

Some tips before you continue

There will invariably be problems, so here are some tips to help get you unstuck:

Exiting the console

To exit the console, hold the CTRL key and press ], then press Enter.

Reconnecting to the console:

To reconnect to the console, type virsh console nixos

Deleting everything and starting over

If everything gets completely broken, here’s how to start over fresh:

  • Stop the VM by typing virsh destroy nixos (turns off the machine)
  • Remove the domain by typing virsh undefine nixos --nvram (deletes the VM)
  • If you want the disk image gone also, you must delete it manually (wherever you put my-nixos-disk-image.qcow2)

Accessing the VM from your host

Use the virsh command to access the VM from the host. It’s a good idea to familiarize yourself with virsh .

1$ virsh list
2 Id   Name    State
3-----------------------
4 13   nixos   running

Getting the guest’s IP address

You can do this within the guest by typing ip a, or you can do it from the host side using virsh’s net-dhcp-leases command:

1$ virsh net-dhcp-leases default
2 Expiry Time           MAC address         Protocol   IP address          Hostname         Client ID or DUID
3-----------------------------------------------------------------------------------------------------------------
4 2021-07-23 21:04:31   52:54:00:33:0c:ee   ipv4       192.168.111.206/24   nixos            01:52:54:00:33:0c:ee

Connecting to the installer via SSH

The console can be a bit funny at times (especially if you resize your shell window), so it’s generally nicer to SSH in. We’ll use a password-based SSH login since it’s only the installer.

  1. Create a password (Note: This is only setting a temporary password for the installer, not the OS you are about to install):
1[nixos@nixos:~]$ passwd
2New password: 
3Retype new password: 
4passwd: password updated successfully
  1. Get the IP address:
1[nixos@nixos:~]$ ip a
2...
32: ens2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
4...
5    inet 192.168.111.206/24 brd 192.168.111.255 scope global dynamic noprefixroute ens2
6...
  1. SSH in to the installer:
1$ ssh nixos@192.168.111.206
2Password: 
3Last login: Sun Aug  1 05:39:07 2021
4
5[nixos@nixos:~]$

Installing NixOS

Switch to root

Doing the installation process as root makes it less cumbersome, and it’s safe since you can’t damage the installer ISO image:

1[nixos@nixos:~]$ sudo su -
2
3[root@nixos:~]#

Setup the disk

This follows the example in the NixOS manual , except that your disk is /dev/vda.

 1parted --script /dev/vda -- mklabel gpt
 2parted --script /dev/vda -- mkpart primary 512MiB -8GiB
 3parted --script /dev/vda -- mkpart primary linux-swap -8GiB 100%
 4parted --script /dev/vda -- mkpart ESP fat32 1MiB 512MiB
 5parted --script /dev/vda -- set 3 esp on
 6mkfs.ext4 -F -L nixos /dev/vda1
 7mkswap -L swap /dev/vda2
 8mkfs.fat -F 32 -n boot /dev/vda3
 9mount /dev/disk/by-label/nixos /mnt
10mkdir -p /mnt/boot
11mount /dev/disk/by-label/boot /mnt/boot
12swapon /dev/vda2
13nixos-generate-config --root /mnt

Customize your install

At this point, you can customize your configuration before installing. Configuration happens via configuration.nix, and the default config comes with a number of commented-out suggestions. Normally, you’d keep your configuration files in a repository and copy them in to the machine being provisioned.

To edit your configuration:

1[root@nixos:~]# nano /mnt/etc/nixos/configuration.nix

Once you’re happy with your configuration, press CTRL-X and save the file to exit the editor.

Configuration: Add an admin user

It’s a good idea to create an admin user for yourself because logging in as root is dangerous. Here’s an example user with admin privileges:

 1  users.users.myuser = {
 2    isNormalUser = true;
 3    home = "/home/myuser";
 4    description = "My example admin user";
 5    # wheel allows sudo, networkmanager allows network modifications
 6    extraGroups = [ "wheel" "networkmanager" ];
 7    # For password login (works with console and SSH):
 8    hashedPassword = "$6$Cc5l1Gyv2gP$Mw0RKFkH719QCZAggQDTJIDcE4HoHFEYUqS71H0FVA/AHR4BJEWhfyPaR3RKiz3WsMsDp1di4oPX3b1s3s6Jt.";
 9    # For SSH key login (works with SSH only):
10    openssh.authorizedKeys.keys = [ "ssh-dss AAAAB3Nza... myuser@foobar" ];
11  };

hashedPassword can be generated using mkpasswd:

1[root@nixos:~]# mkpasswd -m sha-512
2Password: 
3$6$Cc5l1Gyv2gP$Mw0RKFkH719QCZAggQDTJIDcE4HoHFEYUqS71H0FVA/AHR4BJEWhfyPaR3RKiz3WsMsDp1di4oPX3b1s3s6Jt.

Configuration: Enable SSH

You can also turn on SSH so that you can connect via secure shell after rebooting (otherwise only the console will work):

1  services.openssh.enable = true; 

Run the installer

Once you’re happy with your configuration, it’s time to install the OS:

1[root@nixos:~]# nixos-install

If you’ve made any mistakes, it will print out error messages detailing what you need to fix in your configuration.nix.

The last installer step will ask you to set the root password (you can use nixos-install --no-root-passwd to disable this and leave it blank):

1setting root password...
2Enter new UNIX password: ***
3Retype new UNIX password: ***

Reboot

This will cause it to reboot into your newly installed disk:

 1[root@nixos:~]# reboot
 2
 3Domain creation completed.
 4Restarting guest.
 5Connected to domain nixos
 6Escape character is ^]
 7
 8
 9<<< Welcome to NixOS 21.05.1970.11c662074e2 (x86_64) - hvc0 >>>
10
11Run 'nixos-help' for the NixOS manual.
12
13nixos login: 

Log in as the admin user you created (or you can log in via SSH if you enbled it). If you need to make further changes to the configuration, edit /etc/nixos/configuration.nix and then build the new configuration:

1nixos-rebuild switch

At this point, you have a functional NixOS in a virtual machine. You’re at the equivalent of chapter 3 in the NixOS manual , and can now start configuring your OS .

Enjoy!


On Endianness
About Me