NixOS virtual machines#
One of the most important features of NixOS is the ability to configure the entire system declaratively, including packages to be installed, services to be run, as well as other settings and options.
NixOS configurations can be used to test and use NixOS using a virtual machine, independent of an installation on a “bare metal” computer.
What will you learn?#
This tutorial serves as an introduction creating NixOS virtual machines. Virtual machines are a practical tool for experimenting with or debugging NixOS configurations.
What do you need?#
A Linux system with virtualisation support
(optional) A graphical environment for running a graphical virtual machine
A working Nix installation
Basic knowledge of the Nix language
Important
A NixOS configuration is a Nix language function following the NixOS module convention. For a thorough treatment of the module system, check the Module system deep dive tutorial.
Starting from a default NixOS configuration#
Note
You can also skip this section and copy the sample configuration for this tutorial into a file configuration.nix
in the current directory.
Use the nixos-generate-config
command to create a configuration file that contains some useful defaults and configuration suggestions.
The configuration produced from the following setup also is used for the NixOS minimal ISO image:
nix-shell -I nixpkgs=channel:nixos-24.05 -p "$(cat <<EOF
let
pkgs = import <nixpkgs> { config = {}; overlays = []; };
iso-config = pkgs.path + /nixos/modules/installer/cd-dvd/installation-cd-minimal.nix;
nixos = pkgs.nixos iso-config;
in nixos.config.system.build.nixos-generate-config
EOF
)"
Detailed explanation
This nix-shell
invocation creates an environment based on Nixpkgs obtained from a channel and adds to it a derivation that is described by the Nix expression passed as a string to the -p
option.
That Nix expression:
Takes the configuration file for the minimal ISO image from the obtained version of Nixpkgs found in the lookup path
<nixpkgs>
Evaluates that NixOS configuration with
pkgs.nixos
Returns the derivation which produces the
nixos-generate-config
executable from the evaluated configuration
Create a NixOS configuration in your working directory:
[nix-shell:~]$ nixos-generate-config --dir ./
Note
By default, when no --dir
is specified, the generated configuration file is written to /etc/nixos/configuration.nix
, which typically requires sudo
permissions.
In the working directory you will then find two files:
hardware-configuration.nix
is specific to the hardwarenix-generate-config
is being run on.You can ignore that file for this tutorial because it has no effect inside a virtual machine.
configuration.nix
contains various suggestions and comments for the initial setup of a desktop computer.
The default NixOS configuration without comments is:
1{ config, pkgs, ... }:
2{
3 imports = [ ./hardware-configuration.nix ];
4
5 boot.loader.systemd-boot.enable = true;
6 boot.loader.efi.canTouchEfiVariables = true;
7
8 system.stateVersion = "24.05";
9}
To be able to log in, add the following lines to the returned attribute set:
1 users.users.alice = {
2 isNormalUser = true;
3 extraGroups = [ "wheel" ];
4 };
Note
A configuration generated with nixos-generate-config
contains this user configuration commented out.
Additionally, you need to specify a password for this user.
For the purpose of demonstration only, you specify an insecure, plain text password by adding the initialPassword
option to the user configuration:
1 initialPassword = "test";
We add two lightweight programs as an example:
1 environment.systemPackages = with pkgs; [
2 cowsay
3 lolcat
4 ];
Warning
Do not use plain text passwords outside of this example unless you know what you are doing. See initialHashedPassword
or ssh.authorizedKeys
for more secure alternatives.
This tutorial focuses on testing NixOS configurations on a virtual machine.
Therefore you will remove the reference to hardware-configuration.nix
:
- imports = [ ./hardware-configuration.nix ];
Sample configuration
The complete configuration.nix
file looks like this:
1{ config, pkgs, ... }:
2{
3 boot.loader.systemd-boot.enable = true;
4 boot.loader.efi.canTouchEfiVariables = true;
5
6 users.users.alice = {
7 isNormalUser = true;
8 extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user.
9 initialPassword = "test";
10 };
11
12 environment.systemPackages = with pkgs; [
13 cowsay
14 lolcat
15 ];
16
17 system.stateVersion = "24.05";
18}
Creating a QEMU based virtual machine from a NixOS configuration
A NixOS virtual machine is created with the nix-build
command:
$ nix-build '<nixpkgs/nixos>' -A vm -I nixpkgs=channel:nixos-24.05 -I nixos-config=./configuration.nix
This command builds the attribute vm
from the nixos-24.05
release of NixOS, using the NixOS configuration as specified in the relative path.
Detailed explanation
The positional argument to
nix-build
is a path to the derivation to be built. That path can be obtained from a Nix expression that evaluates to a derivation.The virtual machine build helper is defined in NixOS, which is part of the
nixpkgs
repository. Therefore we use the lookup path<nixpkgs/nixos>
.The
-A
option specifies the attribute to pick from the provided Nix expression<nixpkgs/nixos>
.To build the virtual machine, we choose the
vm
attribute as defined innixos/default.nix
.The
-I
option prepends entries to the search path.Here we set
nixpkgs
to refer to a specific version of Nixpkgs and setnix-config
to theconfiguration.nix
file in the current directory.
Running the virtual machine
The previous command created a link with the name result
in the working directory.
It links to the directory that contains the virtual machine.
$ ls -R ./result
result:
bin system
result/bin:
run-nixos-vm
Run the virtual machine:
$ QEMU_KERNEL_PARAMS=console=ttyS0 ./result/bin/run-nixos-vm -nographic; reset
This command will run QEMU in the current terminal due to -nographic
.
console=ttyS0
will also show the boot process, which ends at the console login screen.
Log in as alice
with the password test
.
Check that the programs are indeed available as specified:
$ cowsay hello | lolcat
Exit the virtual machine by shutting it down:
$ sudo poweroff
Note
If you forgot to add the user to wheel
or didn’t set a password, stop the virtual machine from a different terminal:
$ sudo pkill qemu
Running the virtual machine will create a nixos.qcow2
file in the current directory.
This disk image file contains the dynamic state of the virtual machine.
It can interfere with debugging as it keeps the state of previous runs, for example the user password.
Delete this file when you change the configuration:
$ rm nixos.qcow2
Running GNOME on a graphical VM
To create a virtual machine with a graphical user interface, add the following lines to the configuration:
1 # Enable the X11 windowing system.
2 services.xserver.enable = true;
3
4 # Enable the GNOME Desktop Environment.
5 services.xserver.displayManager.gdm.enable = true;
6 services.xserver.desktopManager.gnome.enable = true;
These three lines activate X11, the GDM display manager (to be able to login) and Gnome as desktop manager.
Tip
You can also use the installation-cd-graphical-gnome.nix
module to generate the configuration file from scratch:
nix-shell -I nixpkgs=channel:nixos-24.05 -p "$(cat <<EOF
let
pkgs = import <nixpkgs> { config = {}; overlays = []; };
iso-config = pkgs.path + /nixos/modules/installer/cd-dvd/installation-cd-graphical-gnome.nix;
nixos = pkgs.nixos iso-config;
in nixos.config.system.build.nixos-generate-config
EOF
)"
$ nixos-generate-config --dir ./
The complete configuration.nix
file looks like this:
1{ config, pkgs, ... }:
2{
3 boot.loader.systemd-boot.enable = true;
4 boot.loader.efi.canTouchEfiVariables = true;
5
6 services.xserver.enable = true;
7
8 services.xserver.displayManager.gdm.enable = true;
9 services.xserver.desktopManager.gnome.enable = true;
10
11 users.users.alice = {
12 isNormalUser = true;
13 extraGroups = [ "wheel" ];
14 initialPassword = "test";
15 };
16
17 system.stateVersion = "24.05";
18}
To get graphical output, run the virtual machine without special options:
$ nix-build '<nixpkgs/nixos>' -A vm -I nixpkgs=channel:nixos-24.05 -I nixos-config=./configuration.nix
$ ./result/bin/run-nixos-vm
Running Sway as Wayland compositor on a VM#
To change to a Wayland compositor, disable services.xserver.desktopManager.gnome
and enable programs.sway
:
- services.xserver.desktopManager.gnome.enable = true;
+ programs.sway.enable = true;
Note
Running Wayland compositors in a virtual machine might lead to complications with the display drivers used by QEMU.
You need to choose from the available drivers one that is compatible with Sway.
See QEMU User Documentation for options.
One possibility is the virtio-vga
driver:
$ ./result/bin/run-nixos-vm -device virtio-vga
Arguments to QEMU can also be added to the configuration file:
1{ config, pkgs, ... }:
2{
3 boot.loader.systemd-boot.enable = true;
4 boot.loader.efi.canTouchEfiVariables = true;
5
6 services.xserver.enable = true;
7
8 services.xserver.displayManager.gdm.enable = true;
9 programs.sway.enable = true;
10
11 imports = [ <nixpkgs/nixos/modules/virtualisation/qemu-vm.nix> ];
12 virtualisation.qemu.options = [
13 "-device virtio-vga"
14 ];
15
16 users.users.alice = {
17 isNormalUser = true;
18 extraGroups = [ "wheel" ];
19 initialPassword = "test";
20 };
21
22 system.stateVersion = "24.05";
23}
The NixOS manual has chapters on X11 and Wayland listing alternative window managers.
References#
QEMU User Documentation for more runtime options
NixOS option search:
virtualisation.qemu
for declarative virtual machine configuration