├── .gitmodules ├── README.md ├── grub-test-vm └── configuration.nix ├── setup-git-hooks └── submodules-update /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "nixpkgs"] 2 | path = nixpkgs 3 | url = https://github.com/nh2/nixpkgs 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nixos-vm-examples 2 | 3 | Some examples of how to declare VMs running [NixOS](https://nixos.org), building them with nix, and doing things inside. 4 | 5 | 6 | ## Motivation 7 | 8 | NixOS makes it easy to build and run all kinds of VM images. This is especially when 9 | 10 | * testing configuration changes before applying them to real hardware 11 | * testing changes to NixOS code itself 12 | * building reproducible environments for others to reproduce issues or results 13 | 14 | While the individual NixOS modules involved are well-documented, a set of good examples can help you to build a VM for your use case. 15 | 16 | 17 | ## Examples 18 | 19 | * [`grub-test-vm`](./grub-test-vm/): 20 | 21 | QEMU VM in which you can run `nixos-rebuild` to test changes to NixOS's GRUB bootloader installer. 22 | 23 | Contributions of more examples are welcome! 24 | 25 | They should be well-commented and contain running instructions for beginners (see the existing examples). 26 | 27 | 28 | ## Usage 29 | 30 | Clone this repo with `git clone --recursive`, because it contains a submodule to pin `nixpkgs`. 31 | 32 | After switching branches/commits, run `git submodule update --init --recursive` to ensure the submodule is updated. 33 | Alternatively, run `./setup-git-hooks` to enable automatic submodule updating upon `git checkout` and `git rebase`. 34 | -------------------------------------------------------------------------------- /grub-test-vm/configuration.nix: -------------------------------------------------------------------------------- 1 | # Inspired by: 2 | # 3 | # * https://nixos.mayflower.consulting/blog/2018/09/11/custom-images/ 4 | # * http://blog.patapon.info/nixos-local-vm/#accessing-the-vm-with-ssh 5 | # 6 | # Build VM using: 7 | # 8 | # NIX_PATH=.. nix-build '' -A vm --arg configuration ./configuration.nix 9 | # 10 | # The `./` is important, as it needs to be a nix path literal. 11 | # Run VM using: 12 | # 13 | # rm -f nixos.qcow2 && result/bin/run-nixos-vm 14 | # 15 | # Depending on your permissions you may have to use `sudo` for running. 16 | # A QEMU window will pop up and you can log in as `root` with empty password. 17 | # 18 | # Even better, with SSH: 19 | # 20 | # rm -f nixos.qcow2 && env QEMU_NET_OPTS=hostfwd=tcp::2221-:22 result/bin/run-nixos-vm 21 | # 22 | # Then you can ssh in using: 23 | # 24 | # ssh -oUserKnownHostsFile=/dev/null -oStrictHostKeyChecking=no root@localhost -p 2221 25 | # 26 | # Note by default `ping` will not work, but other Internet stuff will, see 27 | # https://wiki.qemu.org/Documentation/Networking#User_Networking_.28SLIRP.29 28 | # 29 | # Note that running `nixos-rebuild` in the VM may do a lot of downloads, 30 | # even though the files it downloads are apparently already present 31 | # in the nix store, see: 32 | # https://discourse.nixos.org/t/how-to-build-a-nixos-vm-with-nix-in-which-nixos-rebuild-is-a-no-op/7937 33 | 34 | { pkgs, lib, config, ... }: 35 | 36 | with lib; 37 | let 38 | mount_guest_path = "/root/host-dir"; 39 | mount_host_path = toString ../.; # our `nixos-vm-examples` dir 40 | mount_tag = "hostdir"; # just a label tag for qemu mounts 41 | in 42 | { 43 | imports = [ 44 | 45 | 46 | ]; 47 | 48 | config = { 49 | services.qemuGuest.enable = true; 50 | 51 | fileSystems."/" = { 52 | device = "/dev/disk/by-label/nixos"; 53 | fsType = "ext4"; 54 | autoResize = true; 55 | }; 56 | 57 | boot = { 58 | growPartition = true; 59 | kernelParams = [ "console=ttyS0 boot.shell_on_fail" ]; 60 | loader.timeout = 5; 61 | # Not set because `qemu-vm.nix` overrides it anyway: 62 | # loader.grub.device = "/dev/vda"; 63 | 64 | # Mount nixpkgs submodule at `/root/nixpkgs` in guest. 65 | initrd.postMountCommands = '' 66 | mkdir -p "$targetRoot/${mount_guest_path}" 67 | mount -t 9p "${mount_tag}" "$targetRoot/${mount_guest_path}" -o trans=virtio,version=9p2000.L,cache=none 68 | ''; 69 | 70 | # This is the functionality we want to test. 71 | # From inside the VM, you can run: 72 | # cd host-dir 73 | # NIX_PATH=.:nixos-config=$PWD/grub-test-vm/configuration.nix nixos-rebuild switch --install-bootloader --fast 74 | loader.grub.extraGrubInstallArgs = [ 75 | # Uncomment to try this change: 76 | # "--modules=nativedisk ahci pata part_gpt part_msdos diskfilter mdraid1x lvm ext2" 77 | ]; 78 | 79 | # Copy VM configuration into guest so that we can use `nixos-rebuild` in there. 80 | postBootCommands = '' 81 | cp ${./configuration.nix} /etc/nixos/configuration.nix 82 | ''; 83 | }; 84 | 85 | virtualisation = { 86 | diskSize = 8000; # MB 87 | memorySize = 2048; # MB 88 | qemu.options = [ 89 | "-virtfs local,path=${mount_host_path},security_model=none,mount_tag=${mount_tag}" 90 | ]; 91 | 92 | # We don't want to use tmpfs, otherwise the nix store's size will be bounded 93 | # by a fraction of available RAM. 94 | writableStoreUseTmpfs = false; 95 | 96 | # Because we want to test GRUB. 97 | # This may require `system-features = kvm` in your `nix.conf`, and your user 98 | # to be part of the `kvm` group, otherwise you may get: 99 | # Could not access KVM kernel module: Permission denied 100 | useBootLoader = true; 101 | }; 102 | 103 | # So that we can ssh into the VM, see e.g. 104 | # http://blog.patapon.info/nixos-local-vm/#accessing-the-vm-with-ssh 105 | services.openssh.enable = true; 106 | services.openssh.permitRootLogin = "yes"; 107 | # Give root an empty password to ssh in. 108 | users.extraUsers.root.password = ""; 109 | users.mutableUsers = false; 110 | 111 | environment.systemPackages = with pkgs; [ 112 | git 113 | htop 114 | vim 115 | nix-diff 116 | ]; 117 | 118 | }; 119 | } 120 | -------------------------------------------------------------------------------- /setup-git-hooks: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eo pipefail 3 | 4 | # Must be run from top of the git directory 5 | 6 | mkdir -p .git/hooks 7 | rm -f .git/hooks/post-checkout 8 | ln -s ../../submodules-update .git/hooks/post-checkout 9 | ln -s ../../submodules-update .git/hooks/post-rewrite 10 | -------------------------------------------------------------------------------- /submodules-update: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | [ "$SKIP_POST_CHECKOUT_HOOK" = 1 ] && exit 0 3 | git submodule sync && git submodule update --init --recursive 4 | --------------------------------------------------------------------------------