nix module and flake for declarative non-NixOS VMs
Image builds have been dying with "Argument list too long" from sed, mktemp and timeout alike -- commands whose argv is trivial, which is the tell that it was the environment that had grown, not the arguments. The X11 forwarding hint is looked up with `ls -t /tmp/.vmix-display-* | head -1`. Under nullglob a non-matching pattern is removed from the command line rather than passed through literally, so `ls -t` runs with no arguments at all and lists the working directory instead. In a nix build that directory is the build tree, whose newest file is nix's own env-vars dump. The result is that VMIX_DF becomes "env-vars", the SDL branch is taken on a machine with no X at all, and DISPLAY is exported with a slice of the env dump inside it. From that line onward every exec in the build fails with E2BIG. find does the same lookup without depending on how the shell treats an unmatched pattern, and -type f keeps a stray directory out of it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0117qMyjpuXsjpVAcpJbFD8g |
||
|---|---|---|
| lib | ||
| nixos | ||
| .env-export-vmix-cli-local | ||
| .gitignore | ||
| cli.nix | ||
| flake.lock | ||
| flake.nix | ||
| README.md | ||
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
makeImage— unattended install from upstream ISO via QEMUcustomizeImageFold— apply modular templates (registry, apps, drivers)generalize— sysprep + OOBE for deployment to real hardware
Linux pipeline
- Fetch upstream Debian cloud image
customizeImageFold— apply templates viavirt-customize
Key patterns
customizeImageFold—builtins.foldl'over templates for composable layered images_vmixOsType— all images carry"linux"or"windows"metadata for auto-detection- Offline registry — Windows templates use
ControlSet001for offlinevirt-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)