nix module and flake for declarative non-NixOS VMs
Find a file
Git Sagar c213fc4db9 windows/pci: vIOMMU for nested passthrough, and a data disk built with the image
Three things, all in service of putting Proxmox in a VM that can still hand a
GPU to its own guests, and of a Windows VM whose profile survives its OS disk.

pci.viommu.enable emits `-device intel-iommu,intremap=on,caching-mode=on` and
forces kernel-irqchip=split, which interrupt remapping requires. Without an
IOMMU of its own a guest cannot bind a passed-through device to vfio-pci, so
it can never forward one on. The device leads the command line because QEMU
realizes devices in order and intel-iommu must precede what it translates.

pci.vgaPassthrough (default true, so nothing changes for existing VMs) makes
x-vga=on optional. It was forced on the first passthrough device, which is
wrong for a card the guest only forwards onward: it claims the VGA path the
emulated console adapter needs.

customizeImage gains extraDisk, a blank disk attached for the Audit Mode boot
and emitted as the derivation's `data` output. generalize uses it for dataDisk
and profilesDirectory, so the disk is partitioned and the profile relocated
under OOBE in the build VM. That is what removes the need for delayOobeRun --
previously the volume ProfilesDirectory names could not exist until the image
reached real hardware. A second output rather than a directory keeps ${image}
meaning the OS qcow2 for every existing consumer.

generalize also picks up staticIP and profilesDirectory.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0117qMyjpuXsjpVAcpJbFD8g
2026-09-09 22:27:44 -03:00
lib windows/pci: vIOMMU for nested passthrough, and a data disk built with the image 2026-09-09 22:27:44 -03:00
nixos windows/pci: vIOMMU for nested passthrough, and a data disk built with the image 2026-09-09 22:27:44 -03:00
.env-export-vmix-cli-local vmix CLI, laptop images, SDL display 2026-05-23 21:56:51 -03:00
.gitignore fist commit - images lib in a working condition for debian 2024-05-23 16:33:38 +00:00
cli.nix pass XAUTHORITY to builds for SDL display in X11 sessions 2026-05-31 04:51:53 -03:00
flake.lock vmix CLI, laptop images, SDL display 2026-05-23 21:56:51 -03:00
flake.nix fix: use vmix's own locked nixpkgs for all image building 2026-06-15 10:04:52 -03:00
README.md add README with usage, architecture, and examples 2026-06-07 10:46:32 +05:30

vmix

Composable QEMU VM image building and orchestration for NixOS.

What it does

vmix provides:

  • Image building — reproducible Linux (Debian) and Windows qcow2 images via Nix derivations
  • NixOS module — declarative VM management with QEMU in network namespaces
  • CLI tool — build, copy-to-disk, and run images from the command line

Usage

As a flake input

# flake.nix
inputs.vmix.url = "git+https://git.sagar.ch/dotfiles/vmix.nix.git";

# In your NixOS configuration (or globally via serverFunctions)
imports = [ inputs.vmix.nixosModules.default ];

# Use vmixLib via overlay
nixpkgs.overlays = [ inputs.vmix.overlays.default ];
# Then: pkgs.vmixLib.linux, pkgs.vmixLib.windows, pkgs.vmixLib.network

As a CLI

# Enter dev shell
nix develop

# Build an image
vmix build --image windows.images.win10.laptop \
  --generalize username=User,password=secret,hostname=PC

# Write to local disk
vmix copy --image windows.images.win10.laptop \
  --generalize username=User,password=secret \
  --to-disk /dev/sda

# Write to remote disk (streamed via SSH + LZ4)
vmix copy --image windows.images.win10.laptop \
  --generalize username=User,password=secret \
  --to-remote-disk root@10.10.10.100:/dev/nvme0n1

# Boot a built image with QEMU
vmix run ./result --mem 8192 --smp 8 --ahci

Flake outputs

Output Description
overlays.default Nix overlay exposing pkgs.vmixLib
nixosModules.default NixOS module for declarative VM management
lib.x86_64-linux Library functions (images + network utilities)
packages.x86_64-linux.default vmix CLI tool
apps.x86_64-linux.default Runnable vmix app

Repository structure

flake.nix          # Flake entry point
module.nix         # NixOS module export
overlay.nix        # Nix overlay (vmixLib pinned to nixpkgs 25-11)
cli.nix            # CLI tool (build, copy, run)

lib/
  default.nix      # Exports: images (linux + windows) + network
  network.nix      # IPv4/CIDR utilities
  images/
    linux/         # Debian image building + customization
    windows/       # Windows image building + customization
      helpers/     # makeImage, customizeImage, makeWinISO, etc.
      templates/   # Registry tweaks, app installers, essentials
      drivers/     # VirtIO, AMD GPU drivers
      win10/       # Windows 10 LTSC images
      win11/       # Windows 11 images

nixos/
  default.nix      # NixOS module entry point
  networks/        # Network namespace management (LAN, WAN, macvtap)
  vms/             # VM lifecycle management (QEMU, tap devices, DHCP)

Image building

Windows pipeline

  1. makeImage — unattended install from upstream ISO via QEMU
  2. customizeImageFold — apply modular templates (registry, apps, drivers)
  3. generalize — sysprep + OOBE for deployment to real hardware

Linux pipeline

  1. Fetch upstream Debian cloud image
  2. customizeImageFold — apply templates via virt-customize

Key patterns

  • customizeImageFoldbuiltins.foldl' over templates for composable layered images
  • _vmixOsType — all images carry "linux" or "windows" metadata for auto-detection
  • Offline registry — Windows templates use ControlSet001 for offline virt-win-reg --merge

NixOS module

Declare VMs and networks:

vmix.namespaces."lab" = {
  networks.lan1 = {
    subnet = "10.99.1.0/24";
    dhcp.enable = true;
  };
  vms.myvm = {
    image = pkgs.vmixLib.linux.images.debian.v12.upstream;
    memory = 2048;
    cores = 2;
    interfaces.lan1 = { ip = "10.99.1.10"; };
    autostart = true;
  };
};

Features:

  • Network namespaces with WAN (veth), LAN (bridge + dnsmasq), macvtap
  • ACPI graceful shutdown via QMP socket
  • 9p shares with auto-created mount targets
  • Conditional macvtap service (only created when macvtaps are configured)