This is a Nix flake that allows you to run medieval operating systems, some new and some old. Some other candidate names for this flake were:
ProprietareKackscheisse
nix-zoo
Windows 12
menagerie
Inspired by the great Astro and his WFVM flake for building Windows VM images
It took at least a painstaking month to make this project. If you use this project and enjoy it, it would mean a lot if you could sponsor me via GitHub Sponsors, and whilst you're at it, why not sponsor Hercules CI too for making the CI in this repo so incredible.
This code was made whilst listening to Windows96
Massive thanks to the following for various kinds of help!
fetch-macOS-v2.py
, tl;dr it's the Board IDWithout work such as OSX-KVM by Kholia, and macOS-Simple-KVM by Foxlet, a repo like mine could not possibly exist. To bootstrap the project, I use some of the OSX-KVM repo as a Flake input. It contains some qcow2 files that I don't know how to reproduce yet, as noted below in the TODOs.
As pointed out to me on Twitter, Cirrus Labs had made a Hashicorp Packer template to do similar automation by using VNC and Sleeps. The major difference between this and what I am doing, is that I use TCL Expect and Tesseract OCR to more reliably get the same result, without relying as much on sleeps/waits. Additionally, the CI for this repo runs the macOS installer 10 times whenever anything changes, to validate that nothing is broken, and that the function makeDarwinImage
works reliably. There is also a NixOS test that boots the VM, in a VM, and tests that the macOS VM is able to be SSH'd into on port 22.
Currently, only macOS Ventura is supported, building will take *at least 40-50 minutes as the official 11GiB macOS installer is downloaded and used in the Nix sandbox. No user interaction is required. Be patient and sit tight.
nix
commandnix run github:matthewcroughan/NixThePlanet#macos-ventura
You can pass QEMU flags like -vnc
nix run github:matthewcroughan/NixThePlanet#macos-ventura -- -vnc 0.0.0.0:1
To enable the VM as a NixOS service via the nixosModule
enable the macos-ventura module on a nixosConfiguration
in your flake.nix
services.macos-ventura.sshPort
services.macos-ventura.vncDisplayNumber
{
inputs = {
nixtheplanet.url = "github:matthewcroughan/nixtheplanet";
nixpkgs.url = "github:nixos/nixpkgs/nixos-23.05";
};
outputs = { self, nixpkgs, nixtheplanet }: {
nixosConfigurations.my-machine = nixpkgs.lib.nixosSystem {
modules = [
nixtheplanet.nixosModules.macos-ventura
{
services.macos-ventura = {
enable = true;
openFirewall = true;
vncListenAddr = "0.0.0.0";
};
}
];
};
};
}
makeDarwinImage
functionThis flake exports a function makeDarwinImage
which takes a diskSizeBytes
argument in order to influence the disk size of the resulting VM, it could be used like this in a flake.nix
for example
{
inputs = {
nixtheplanet.url = "github:matthewcroughan/nixtheplanet";
nixpkgs.url = "github:nixos/nixpkgs/nixos-23.05";
};
outputs = { self, nixpkgs, nixtheplanet }: {
# Create a 60GB Darwin disk image, two ways of doing the same thing
# x is accessing legacyPackages directly from the flake
# y is applying the overlay from nixtheplanet unto its own instance of nixpkgs
x = nixtheplanet.legacyPackages.x86_64-linux.makeDarwinImage { diskSizeBytes = 60000000000; };
y = (import nixpkgs { system = "x86_64-linux"; overlays = [ nixtheplanet.overlays.default ]; }).makeDarwinImage { diskSizeBytes = 60000000000; };
};
}
Using the makeDarwinImage
function directly, you could increase the size of the macOS image used by services.macos-ventura.enable = true
in your NixOS config as follows:
{ pkgs, ... }:
{
services.macos-ventura = {
enable = true;
package = pkgs.makeDarwinImage { diskSizeBytes = 60000000000; };
};
}
Each of the outputs in this flake have their own image builders and runScript
.
makeMsDos622Image
makeWin30Image
makeWfwg311Image
makeWin98Image
They can each be passed the dosPostInstall
argument arbitrary dos
commands to be ran after Windows has been installed, for example here's how
you can use them to build an image that adds win
to the AUTOEXEC.BAT
makeWin30Image {
dosPostInstall = ''
c:
echo win >> AUTOEXEC.BAT
'';
}
The runScript
is a method of the image builder, for example makeWin30Image {}).runScript
. Additionally there is a makeRunScript
method which can be passed arguments like diskImage
.
(makeWin30Image {}).makeRunScript {
diskImage = makeWin30Image {
dosPostInstall = "echo foo";
};
}
nix
commandnix run github:matthewcroughan/NixThePlanet#msdos622
nix
commandnix run github:matthewcroughan/NixThePlanet#win30
nix
commandnix run github:matthewcroughan/NixThePlanet#wfwg311
nix
commandnix run github:matthewcroughan/NixThePlanet#win98
${pkgs.nix.outPath}/scripts/install.in
runInWin311
and similar functionsrunInDarwinVM
using the makeDarwinImage
primitive$out
for the image builders using vncdo
, would
help with debuggingexpect
and tesseract
together with Nix,
similar to the NixOS Testing Framework to reduce code duplication in this reporunInDos
primitive using telnet and dosbox-x serial, would look
something like:
runInDos ''
c:
echo hello world > file
''
On some CPUs macOS will fail to boot when using multiple cores due to macOS lacking drivers for host CPU timers, this has been encountered on an AMD Ryzen 2700U for example,
If the VM is too slow, Apple's macOS installer can hit race conditions and hang. A retry of the build of the derivation will usually fix this.
Notable changes to the OpenCore-Boot.sh
script for the OSX-KVM repository that
I am copy-pasting into this repo temporarily for bootstrapping purposes are:
snapshot=on
and generating QCOW2 images backed by raw disk images to
improve performance and disk usage during installation phaseI am also changing scripts/run_offline.sh
to automatically partition the Disk,
and not embedding it into the InstallAssistant, to allow for reconfiguration of
the run_offline script in a separate derivation.
In this review, Chris McDonough appears very excited. Apparently, NixThePlanet has the power to make grown men giggle.