UTM on macOS - tgs-jbraun/JumpCloud-Seeding GitHub Wiki
The utm-qemu/ folder deploys a macOS VM in UTM on a Mac with Apple silicon. deploy-macos-vm.zsh duplicates a golden macOS VM as <name>_JCLab_macOS and starts it. The copy gets 4 CPU cores and 4 GiB of RAM.
The test machine is a Mac mini with an M2 chip, 8 GiB of RAM and a 250 GB disk, running UTM 4.7.5. One VM at 4 GiB leaves the other half of the Mac's RAM for macOS itself.
UTM 4.7.5 can't create or install a macOS VM from a script. Its AppleScript make command builds Apple Virtualization VMs as Linux guests only. It can duplicate a VM, so the script copies one you build by hand, the way the Hyper-V tools import golden exports.
UTM 5.0.6, a prerelease, adds scripted macOS installs from an IPSW. The script doesn't use them yet.
- Apple silicon. macOS guests don't run on Intel Macs.
- UTM in
/Applications, from mac.getutm.app. -
gum (MIT license, Charmbracelet) for the menus, spinners and boxes:
brew install gum. - A clone of this repo, but only to run the script on the Mac itself.
- Permission for your terminal to control UTM. macOS asks on the first run.
- In UTM, create a macOS VM (Virtualize > macOS 12+) from an IPSW restore image.
- Set its disk to 40 GB. The script can't resize it later.
- Give it a single network adapter. Only the first adapter carries over to the copy.
- Finish Setup Assistant and install what every lab VM needs.
- Shut it down, and put its name in
GoldenVMinutm-qemu/settings.json.
Put your site's values in utm-qemu/settings.json. Copy settings.example.json and fill it in. Git ignores settings.json, and it never holds a password.
-
GoldenVMis the golden VM's name in UTM. -
ComputerNameandUserare the Mac and its account. The Windows launcher and jclab.py use them.
./utm-qemu/deploy-macos-vm.zsh| Option | Default | Meaning |
|---|---|---|
-n |
Asks, offering the last value | Your name, added to the VM name |
-g |
Asks, offering the last value or GoldenVM from settings.json
|
The golden VM's name in UTM |
- It asks for your name and the golden VM. It remembers both with macOS's
defaultscommand, in~/Library/Preferences/JumpCloud-Seeding.plist. - It checks that the golden VM exists and is shut down, since UTM only duplicates stopped VMs.
- It shows the deployment plan.
- If you already have the lab VM, it offers Cancel (the default), Redeploy or Delete. Delete stops the VM through UTM, waits up to 60 seconds for it to stop, then deletes it through UTM.
- It duplicates the golden VM, sets 4 cores and 4 GiB of RAM, and gives the copy a new random MAC address.
- It starts the VM and waits up to 60 seconds for UTM to report it running. If the start fails, it retries once after 5 seconds. A pop-culture fact appears while the VM starts.
- It shows a results box with the VM's name, size, MAC address and status.
The copy takes almost no disk space at first. UTM duplicates with APFS clones, so the copy shares the golden VM's data and grows only by what it writes. The disk image is sparse, so even the golden VM uses only the space macOS fills, not all 40 GB.
UTM 4.7.5 keeps the golden VM's MAC address on the Apple Virtualization VMs it duplicates, so the script sets a new one. Without it, the copy and the golden VM would likely get the same IP address on UTM's shared network.
The copy shares the golden VM's Mac machine identifier. Don't sign it in to the same Apple Account as the golden VM.
deploy-macos-vm-remote.ps1 runs the script on the Mac over SSH. The Mac needs no copy of this repo: the launcher sends the script and the pop-culture facts inside the SSH command. The Mac writes them to a temporary folder, runs the script, and deletes the folder whether the script succeeds or not. The menus appear in your Windows terminal, and the VM's window opens on the Mac's screen.
The launcher needs only the SSH client built into Windows 10/11 and Windows Server 2019 or later, and it works in Windows PowerShell 5.1. Keep it inside a clone of this repo, because it reads the facts file from the hyper-v folder.
Set up the Mac once:
- Turn on automatic login. UTM is a desktop app, so it needs a logged-in user to run VMs.
- Turn on Remote Login in System Settings > General > Sharing.
- Click the info button next to Remote Login, then turn on "Allow full disk access for remote users". The script needs full disk access over SSH.
- Start the first remote run. When macOS asks on the Mac's screen whether SSH may control UTM, click Allow. The prompt doesn't appear over SSH. Until you allow it, the script fails with "Not authorized to send Apple events" (-1743). The setting is under System Settings > Privacy & Security > Automation.
Then run it from Windows:
.\utm-qemu\deploy-macos-vm-remote.ps1 -ComputerName mac-mini.local -User labadmin| Parameter | Default | Meaning |
|---|---|---|
-ComputerName |
Asks, offering the last value or settings.json
|
The Mac's host name or IP address |
-User |
Asks, offering the last value or settings.json
|
The account on the Mac |
-IdentityFile |
Asks, offering the last key | The private SSH key to sign in with |
-PasswordOnly |
Off | Sign in with the Mac password instead of a key |
-UserName, -Golden
|
Asked by the Mac script | Passed to the Mac script as -n and -g
|
The launcher signs in with an SSH key from %USERPROFILE%\.ssh:
- It lists the key pairs there, plus a "Password only" option, and offers the key you picked last time.
- It checks whether the Mac already accepts the key, with a quick login that can't prompt.
- If the Mac doesn't accept the key yet, the launcher offers to add the public key to
~/.ssh/authorized_keyson the Mac. You enter the Mac password that one time. The launcher doesn't add a key the file already has.
The launcher remembers the Mac, the account and the key in %APPDATA%\JumpCloud-Seeding\utm-remote.json. ssh asks for any password or key passphrase itself, and the launcher never saves one. It runs ssh -t so gum gets a terminal. The Mac script adds /opt/homebrew/bin to its search path, because commands run over SSH skip ~/.zprofile, where Homebrew adds it.
Remote Apple Events (Remote Application Scripting) don't work from Windows. Only another Mac can send them.