# Mac OS X Server 10.6 on Proxmox VE 8.2.2

## Build and Operations Runbook

| Field | Value |
|---|---|
| System | SnowLeopardServer (hostname withheld) |
| VM ID | 143 |
| Site | Withheld |
| Current host node | pveN |
| Virtualisation platform | Proxmox VE 8.2.2 / QEMU 8.1.5 |
| Guest operating system | Mac OS X Server 10.6.8 (build 10K549) |
| Bootloader | Chameleon 2.1 r2069 |
| Status | Operational, remote administration restored |
| Revision | 1.1 |

### Revision history

| Rev | Change |
|---|---|
| 1.0 | Initial build documentation at 10.6.3 |
| 1.1 | 10.6.8 update applied. Documents the AppleVNCServer colour-depth crash and the display adapter change that resolved it. Corrects the storage and snapshot sections, which the build has since moved past. |

---

## 1. Purpose and scope

This document records the working configuration for running Mac OS X Server 10.6 as a virtual machine on the Proxmox VE cluster, together with the procedure used to build it and the operational constraints that apply to it.

The configuration described here is the first combination of firmware, machine type, CPU model, bootloader, display adapter, and device topology that produced a complete and repeatable installation with working remote administration. Several other combinations were evaluated and failed. Those attempts are recorded in Appendix A so that the same ground does not have to be covered again, and so that the reasoning behind each choice remains visible to whoever inherits this system.

### 1.1 Audience

This runbook assumes working familiarity with Proxmox VE administration, QEMU device topology, and the Linux command line. It does not assume prior experience with legacy Mac OS X virtualisation or with the Chameleon bootloader.

### 1.2 Scope

In scope: host preparation, guest configuration, the installation procedure, the 10.6.8 update, remote administration, and the known limitations of the platform.

Out of scope: configuration of the Mac OS X Server services themselves (Open Directory, AFP, Web, Wiki, and so on), backup policy, and the network design of the segment the VM sits on.

### 1.3 Licensing

Apple's software licence agreement for Mac OS X Server restricts installation to Apple-branded hardware. Confirm the licensing position for this deployment with whoever owns the business relationship before the system is used for anything beyond isolated legacy access.

---

## 2. System summary

### 2.1 Design rationale

Snow Leopard predates the UEFI-based Mac boot conventions that modern bootloaders such as OpenCore are built around, and the 10.6 installer volume uses an Apple Partition Map rather than the GPT layout that later releases use. In practice this means that the modern virtualisation recipe of OVMF plus OpenCore, which works well for Catalina and later, does not reliably discover a Snow Leopard installer at all. Three separate OpenCore configurations were tested and none of them presented the installer in the boot picker.

The configuration that worked replaces that stack with the arrangement that was contemporary with the operating system itself: SeaBIOS as firmware, and Chameleon 2.1 as the bootloader. Chameleon performs its own scan for bootable Apple volumes rather than relying on firmware-level discovery, and it handles Apple Partition Map media correctly.

Three further choices were driven by observed failures rather than preference. The CPU model is set to Penryn because Nehalem caused the guest to reset during the Darwin kernel handoff. The installer media was attached as a SATA hard disk rather than as optical media because legacy Apple bootloaders discover Apple-partitioned volumes far more reliably when they are presented as disks. The display adapter is VMware SVGA II rather than the Cirrus default because the Cirrus adapter produced a 16-bit framebuffer that crashed Apple's VNC server on every frame. All three are documented in Appendix A with the specific symptoms that led to them.

### 2.2 Configuration baseline

| Parameter | Value | Reason |
|---|---|---|
| BIOS | SeaBIOS | Required by Chameleon; OpenCore paths were rejected |
| Machine type | pc-q35-2.5 | Known working; Q35 version changes did not affect the outcome |
| CPU model | Penryn | Nehalem reset during kernel handoff |
| Sockets / cores | 1 / 1 | See section 8.1 on the SMP restriction |
| Memory | 4096 MB | Ballooning disabled |
| Display adapter | `vmware,memory=32` | Cirrus default gave a 16-bit framebuffer that crashed AppleVNCServer |
| Network adapter | Intel E1000 | VirtIO is not supported by the guest |
| Tablet pointer | Disabled | Caused USB enumeration stalls in the guest |
| Bootloader media | Chameleon 2.1 r2069 on IDE CD-ROM | SATA attachment caused SerialATAPI reset errors |
| Firmware boot order | ide2 only | Chameleon performs its own volume discovery |

VirtIO devices must not be used for the system disk or the network interface. Snow Leopard has no drivers for them, and substituting VirtIO will produce a guest with no visible disk or no network.

The guest reports `ostype: l26`. This is cosmetic and affects only some Proxmox defaults, but it is inaccurate and worth correcting to `other` during the next maintenance window.

### 2.3 Storage layout

| Device | Contents | Format | Size | Retention |
|---|---|---|---|---|
| sata0 | Installed Mac OS X Server system volume | QCOW2 on NFS-STORE, `discard=on` | 64 GB | Permanent |
| ide2 | Chameleon 2.1 r2069 ISO | ISO on local storage | 22 MB | Permanent, required at every boot |
| unused0 | Stale disk from the abandoned OpenCore attempt | RAW on NFS-STORE | Varies | Delete |

The system volume was initialised inside the installer using Disk Utility with a GUID Partition Table and a single Mac OS Extended (Journaled) volume.

The Snow Leopard installer disk that occupied `sata1` during the build has been detached. The `unused0` RAW image from the OpenCore attempt is still present and should be deleted, though it is not currently blocking anything (see section 8.2).

### 2.4 Architecture

```text
Proxmox VE 8.2.2 / QEMU 8.1.5, node pveN
  |
  +-- KVM module: ignore_msrs = 1  (host-level prerequisite)
  |
  +-- VM 143  SnowLeopardServer
        |
        +-- Firmware .......... SeaBIOS
        +-- Machine ........... pc-q35-2.5
        +-- CPU ............... Penryn, 1 socket x 1 core
        +-- Memory ............ 4096 MB, ballooning off
        +-- SMC ............... isa-applesmc with Apple OSK
        +-- Display ........... VMware SVGA II, 32 MB
        +-- Network ........... Intel E1000 on vmbrN, firewall on
        |
        +-- ide2 .............. Chameleon 2.1 r2069
        +-- sata0 ............. 64 GB QCOW2, Mac OS X Server 10.6.8
        |
        +-- USB keyboard ...... bus ehci-2.0
        +-- USB mouse ......... bus ehci.0 port 2 (recovery only)

Administrative path:
  Workstation --> SSH on a non-default port to server.example.lan
                    +-- SSH shell
                    +-- Screen Sharing over a tunnel to 127.0.0.1:5900
```

Note that the guest's own interface address is on a different subnet (`10.0.0.x`) from the address you connect to (`server.example.lan`). There is address translation between the administrative LAN and the guest segment. This matters when reading `netstat` output from inside the guest and when constructing SSH tunnels, as described in section 7.1.

---

## 3. Host prerequisites

### 3.1 KVM model-specific register handling

This is the single most important host-level setting, and its absence was responsible for the longest-running failure during the build. Without it, the guest entered an immediate reboot loop during Chameleon startup that looked like a bad bootloader image or an unsupported machine type, and considerable time was spent changing Q35 versions before the real cause was identified.

Snow Leopard reads model-specific registers that KVM does not emulate. By default KVM injects a general protection fault on those accesses, which the guest treats as fatal. Setting `ignore_msrs` causes KVM to return zero for unhandled reads and silently discard unhandled writes instead.

Apply the setting at runtime:

```bash
echo 1 > /sys/module/kvm/parameters/ignore_msrs
```

Confirm it took effect. Depending on how the running kernel represents the parameter, the value will read back as either `Y` or `1`:

```bash
cat /sys/module/kvm/parameters/ignore_msrs
```

Make the setting persistent across reboots:

```bash
echo "options kvm ignore_msrs=Y" > /etc/modprobe.d/kvm.conf
update-initramfs -k all -u
```

### 3.2 Cluster-wide applicability

This is a host KVM module parameter, not a guest property, and it does not migrate with the VM. Every node in the cluster that is permitted to host VM 143 must carry the setting, otherwise the guest will fail to boot after a migration or after an HA restart on a node that has not been prepared. Either apply the modprobe configuration to all candidate nodes, or restrict the VM to a defined HA group whose members have all been configured.

Note that `ignore_msrs` weakens the guest-to-host boundary slightly, because it hides guest behaviour that would normally raise a fault. That is an acceptable trade for a legacy workload on a controlled network segment, but it should be a deliberate decision rather than an accident, and it is a reason to keep this VM on nodes where the exposure is understood.

---

## 4. Guest configuration reference

### 4.1 Proxmox configuration

Retrieve the live configuration at any time with:

```bash
qm config 143
```

The configuration should reflect the baseline in section 2.2. The elements that matter most, and which are easy to lose during routine edits through the web interface, are the machine type, the CPU model, the display adapter, the disabled tablet, the IDE attachment of the Chameleon ISO, and the custom arguments described below.

### 4.2 Custom QEMU arguments

Three devices are supplied through the `args` line because Proxmox has no native interface for them. The Apple SMC device is mandatory, since Darwin refuses to boot without a system management controller presenting Apple's OSK string. The two USB devices exist because the default Proxmox input configuration does not work with this guest.

```text
args: -device isa-applesmc,osk="ourhardworkbythesewordsguardedpleasedontsteal(c)AppleComputerInc" -device usb-mouse,id=mouse,bus=ehci.0,port=2 -device usb-kbd,id=keyboard,bus=ehci-2.0
```

The OSK string is case-sensitive and must be reproduced exactly, including the parenthesised copyright marker.

The keyboard is attached to the second EHCI controller. Attaching it to the first controller produced USB enumeration failures in the guest and left the installer without usable keyboard input. This was the second most time-consuming problem in the build after the MSR issue.

Do not add a bare `-usb` flag to the arguments. Proxmox already instantiates the ICH9 USB controllers as part of the Q35 machine definition, and a second set collides with them:

```text
PCI: slot 29 function 7 not available for ich9-usb-ehci1
```

### 4.3 Verifying device placement

Bus names such as `ehci-2.0` are derived from device identifiers that Proxmox assigns when it builds the QEMU command line, and they are not guaranteed to be stable across Proxmox or QEMU upgrades. If the guest loses keyboard input after a host upgrade, confirm the actual controller topology rather than assuming the argument is still valid. From the QEMU monitor for the running VM:

```bash
qm monitor 143
```

Then, at the monitor prompt:

```text
info qtree
```

Locate the EHCI controllers in the output and confirm that the bus name referenced in the `args` line still exists.

---

## 5. Build procedure

The following is the procedure that produced the working system. It is recorded in full so that the VM can be rebuilt from scratch if required.

### 5.1 Create the virtual machine

Create the VM with the baseline from section 2.2. Add a 64 GB QCOW2 disk on `NFS-STORE` attached as `sata0`. Do not select VirtIO for either the disk or the network adapter. Set the display adapter to `vmware` with 32 MB. Disable ballooning and disable the tablet pointer before first boot.

### 5.2 Verify and stage the installer media

Verify the installer image before using it. A corrupt or truncated image produces failures that are easily mistaken for configuration problems.

```bash
sha1sum MAC_OS_X_10-6-3_SNOW_LEOPARD_SERVER.ISO
```

The expected values are:

| Property | Value |
|---|---|
| Size | 7,619,510,272 bytes |
| SHA-1 | 1244e5e3afc73a2cba792f57dae54bb7f3a5575a |

The image contains an Apple Partition Map with an HFS installer volume. Partition inspection on the host shows `Apple_partition_map`, `Apple_Drive_ATAPI`, `Apple_Free`, and `Mac_OS_X.hfs`.

Convert the image and import it into Proxmox storage:

```bash
qemu-img convert -p -f raw -O qcow2 \
  /var/lib/vz/template/iso/MAC_OS_X_10-6-3_SNOW_LEOPARD_SERVER.ISO \
  /tmp/SnowLeopardServer-Installer.qcow2

qm disk import 143 /tmp/SnowLeopardServer-Installer.qcow2 NFS-STORE --format qcow2
```

Attach the resulting disk as `sata1`.

The `--format qcow2` flag is important. Without it, `qm disk import` writes in the target storage's default format, which is why the original import landed on the NFS store as RAW. That produced the stale `unused0` RAW image still attached to this VM.

### 5.3 Attach the bootloader

Attach `Chameleon-2.1-r2069.iso` as an IDE CD-ROM on `ide2`, and set the firmware boot order to `ide2` only. Chameleon does not need any other device in the boot order, because it scans for bootable Apple volumes itself once it has started.

The ISO should be a valid El Torito no-emulation boot image. Confirm this with `file` if there is any doubt about the source of the image.

Chameleon must be attached to IDE rather than SATA. When it was presented as a SATA optical device, the guest logged repeated SerialATAPI reconfiguration and reset errors during boot. Moving it to IDE resolved the fatal cases, although some SerialATAPI warnings may still appear harmlessly during startup.

### 5.4 Boot Chameleon and start the installer

Start the VM. Chameleon should enumerate the attached volumes and present an entry named `Mac OS X Server Install Disc`.

Select that entry, then enter the following boot arguments before continuing:

```text
cpus=1 -v
```

The `cpus=1` argument restricts the Darwin kernel to a single processor, which is required because 10.6.3 panics almost immediately under SMP in this environment. The `-v` argument enables verbose boot, which is worth keeping for the whole build because it turns an opaque grey screen into a readable log when something goes wrong.

### 5.5 Initialise the destination volume

The 64 GB disk will not appear as an installation target until it has been partitioned. From the installer menu bar, open Utilities and then Disk Utility. Select the 64 GB QEMU disk, and partition it with a GUID Partition Table and a single Mac OS Extended (Journaled) volume.

Quit Disk Utility and return to the installer. The volume will now be selectable as a destination.

### 5.6 Run the installation

The installation is extremely slow in this configuration and completed over the course of several hours.

The progress indicator is not trustworthy. The estimated time remaining routinely sat unchanged for ten minutes or more of real time before advancing by a single minute, and the progress animation appeared frozen for long stretches. This behaviour is expected and is not by itself evidence of a failure.

Do not restart the VM because the interface looks motionless. Intervene only on clear evidence of a permanent failure, which means a kernel panic message on the verbose console, a reboot loop, or a guest that has stopped generating any host-side CPU activity over an extended period. Host CPU usage for the VM process is the most reliable signal available from outside the guest.

### 5.7 First boot

After the installation completes, boot through Chameleon again and select the installed system volume rather than the installer. Continue to supply `cpus=1 -v` at the prompt.

Complete the Mac OS X Server Setup Assistant. Confirm that the guest has obtained a DHCP lease through the E1000 adapter before proceeding, since the remainder of the work depends on network access to the guest.

---

## 6. Post-installation

### 6.1 Apply the 10.6.8 Server combo update

Apply the Mac OS X Server 10.6.8 Combo Update. Use the Server package rather than the client Snow Leopard combo update; the two are not interchangeable and applying the client package to a Server installation will produce an inconsistent system.

Be aware that the update replaces the Apple Remote Desktop components. On this system it took `ARDAgent.app` and `AppleVNCServer.bundle` to version 3.5.4 and broke remote administration outright, for the reasons given in section 6.3. Plan for the guest to be reachable only over SSH and the Proxmox console until that is dealt with.

### 6.2 Verification

After the update completes and the guest has rebooted successfully:

```bash
sw_vers
uname -a
sysctl hw.ncpu
```

`sw_vers` should report version 10.6.8, build 10K549.

### 6.3 Display adapter and colour depth

**This step is a prerequisite for remote administration and must be completed before configuring Screen Sharing.**

Apple's `AppleVNCServer` copies the console framebuffer scanline by scanline and assumes 32 bits per pixel. With the Proxmox default Cirrus adapter, the guest ran at 1024x768 in 16-bit ARGB1555. The server therefore read 4096 bytes per row from a framebuffer whose rows were 2048 bytes, ran 2048 bytes past the end of the mapped region on every frame, and took a bus error. Full diagnosis in Appendix A.5.

Switch the display adapter on the host:

```bash
qm set 143 --vga vmware,memory=32
```

Shut the guest down cleanly and start it again. A live migration or a reset is not sufficient, since the adapter is established at VM start.

Verify from inside the guest:

```bash
system_profiler SPDisplaysDataType
```

The adapter should now report vendor ID `0x15ad` and device ID `0x0405`, which is VMware SVGA II. If it still reports vendor `0x1013` (Cirrus), the change did not take effect and there is no point configuring Screen Sharing, because it will simply resume the crash loop.

Two things about this adapter are worth knowing:

The guest reports 3 MB of VRAM regardless of the 32 MB allocated on the host. That is the adapter's own reporting and is not a problem in itself, since it is enough for the mode in use.

There is no OS X driver for VMware SVGA II, so `system_profiler` reports a bare `Display Connector:` with no resolution or pixel depth listed, and no kernel extension is loaded. The guest runs in a plain VESA mode. This is cosmetically unsatisfying but functionally correct: the mode is 32-bit, which is all the VNC server requires.

### 6.4 Resolution

Increasing the resolution beyond the default VESA mode has not succeeded. An attempt to set 1920x1080x32 did not take effect.

The likely reason is that Chameleon selects a mode from the VESA mode table the adapter advertises and cannot request one that is not in that list. With no OS X driver present, the available modes are whatever the VMware SVGA II VESA BIOS exposes, which does not appear to include widescreen modes at that size.

Two further constraints are worth recording before anyone spends time on this:

The mechanism for persisting Chameleon boot settings on this system is unverified. Chameleon 2.1 reads `/Extra/org.chameleon.Boot.plist`, but it locates that file relative to the volume it booted from, and here it boots from a read-only ISO. Whether it also searches the HFS+ system volume has not been established. Note that `/Library/Preferences/SystemConfiguration/com.apple.Boot.plist` is read by Apple's own `boot.efi` on genuine hardware and is not consulted by Chameleon, so editing it will have no effect.

Installing Chameleon to the system disk rather than booting it from CD would give a writable `/Extra` and remove the dependency on removable media. That is worth doing on its own merits and would also settle this question. It is item 4 in the backlog.

Since remote administration works at the current resolution, this is a comfort issue rather than a functional one.

### 6.5 Enable remote management

With the display adapter corrected, activate Remote Management scoped to a named account:

```bash
sudo /System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart \
  -activate -configure -access -on -users adminuser -privs -all -restart -agent -console
```

Prefer `-users <name>` over `-allowAccessFor -allUsers`. The latter grants remote control to every local account and there is no reason to configure it that way on a system with a known administrator.

Verify:

```bash
ps aux | grep '[A]ppleVNCServer'
netstat -an | grep 5900
ls -lt /Library/Logs/DiagnosticReports/ | head -5
```

A running `AppleVNCServer` process, a persistent `*.5900 LISTEN` socket, and no crash report newer than the last reboot together confirm success.

Note that `launchctl list` will not show a job named `com.apple.AppleVNCServer`. On this system the `com.apple.ServerSetup_AppleVNCServer` launchd job is unloaded, and the VNC server runs as a child of `ARDAgent` instead. This is a working arrangement and the absence of a launchd entry is not a fault. Use `ps` rather than `launchctl` to check whether the server is alive.

---

## 7. Remote administration

### 7.1 Screen Sharing over an SSH tunnel

Screen Sharing on this guest listens on TCP 5900 and carries no meaningful transport security. Do not expose that port between network segments. Open an SSH tunnel from the administrative workstation instead. SSH on this guest listens on a non-default port:

```bash
ssh -p 2222 -L 5901:127.0.0.1:5900 adminuser@server.example.lan
```

The tunnel destination must be `127.0.0.1`, resolved from the guest's own perspective. Using the guest's external address as the forward target fails, because address translation sits between the administrative LAN and the guest segment:

```text
ssh -L 5901:server.example.lan:5900 ...   -->  Operation timed out
ssh -L 5901:127.0.0.1:5900 ...        -->  works
```

Local ports below 1024 also require privilege on the workstation, which is why an early attempt at `-L 446:127.0.0.1:445` was refused with `bind: Permission denied`. Use high-numbered local ports.

With the tunnel established, connect from Finder using Go and then Connect to Server, with the address:

```text
vnc://localhost:5901
```

This gives correct pointer behaviour, a responsive desktop, and no additional exposed service. It is the normal method of graphical administration for this system.

### 7.2 Console access

The Proxmox noVNC console remains available and is the correct tool for recovery work: reaching the Chameleon boot prompt, reading a verbose boot, or diagnosing a guest that has lost its network. It is not suitable for routine use, because pointer synchronisation through the relative USB mouse is poor enough to make ordinary interface work impractical.

### 7.3 Interpreting netstat from inside the guest

Three things in the guest's `netstat` output look wrong at first glance and are not:

`tcp46 *.5900 LISTEN` is a single dual-stack socket accepting both IPv4 and IPv6 connections, not two conflicting listeners.

Connections appear with a local address of `10.0.0.106` rather than `server.example.lan`, because the latter is the translated address you connect to and the former is the guest's own interface.

A run of entries in `TIME_WAIT` with no `ESTABLISHED` entry is the signature of a server accepting connections and then dying. During the crash loop this was the clearest single indicator that the problem was server-side rather than a firewall or a tunnel fault.

---

## 8. Known constraints and outstanding work

### 8.1 CPU configuration

With both virtual CPUs active, Mac OS X Server 10.6.3 panicked almost immediately during boot:

```text
panic(cpu 1 ...): Spinlock acquisition timed out
```

The panic occurred in XNU 1504.3.12 and implicated CPU 1. The workaround during the build was the `cpus=1` boot argument.

The VM is now configured with a single core, which makes the boot argument redundant. Testing SMP under 10.6.8 therefore requires setting `cores: 2` in the Proxmox configuration first, and there is no longer any reason to expect a different outcome without doing so. If that test is attempted:

1. Take a snapshot.
2. Set `cores` to 2 and shut the guest down cleanly.
3. Boot through Chameleon with `-v` alone, omitting `cpus=1`.
4. Watch the verbose boot for the spinlock panic.
5. If the guest reaches the desktop, confirm the processor count with `sysctl hw.ncpu`, which should report 2.

Change one variable at a time. Do not adjust the CPU model, core count, and boot arguments together, because the failure modes are similar enough that a combined change gives no useful information about which element was responsible.

### 8.2 Snapshots

Snapshots are working. The VM currently has a parent snapshot named `Pre-Display-Post-1068`, taken after the 10.6.8 update and before the display adapter change.

The earlier report that snapshots were unavailable was resolved by detaching the Snow Leopard installer disk from `sata1`. The remaining `unused0` RAW image from the abandoned OpenCore attempt is evidently not blocking snapshot creation, but it is consuming NFS space for nothing and should be deleted.

Take a clean snapshot now that remote administration is working, before any further experimentation.

### 8.3 Firewall state requires restoration

During the VNC diagnosis the guest firewall was disabled to rule it out as a cause. Two changes remain in place and must be reverted:

```bash
sudo ipfw list
```

currently returns only `65535 allow ip from any to any`, meaning all filtering is off. The application firewall socket filter kext was also unloaded with `socketfilterfw -d`.

A reboot will reload the ipfw ruleset from the firewall service configuration, or the firewall can be re-enabled through Server Admin. Confirm afterwards that the original ruleset is back, which included the deny-by-default rule at 65534 and explicit allows for SSH, port 311, and port 625. This is the highest-priority item in the backlog: the guest is currently running with no host-level filtering at all.

### 8.4 Credential exposure in logs

The string `Secret123` was passed as an argument to `kickstart` under `sudo` on two occasions and is recorded in cleartext in `/var/log/system.log`. Any VNC password set during the diagnosis should be considered compromised and changed. When setting a VNC password, avoid passing it on a command line under `sudo` for this reason.

The manually written `/Library/Preferences/com.apple.RemoteManagement.vncpasswd` file and the hand-set `VNCServerLegacy` and `VNCPasswordValid` preference keys were removed during the diagnosis and the preference domain was reset. The current working configuration does not depend on any of them.

### 8.5 Pointer input through the Proxmox console

Proxmox's absolute pointer device caused USB enumeration trouble in the guest, logged as:

```text
IOUSBFamily is having trouble enumerating a USB device
```

along with extended stalls during boot. The tablet was therefore disabled and replaced with a relative USB mouse, which works but tracks poorly through the web console.

Archived QemuUSBTablet 1.1 and 1.2 installer packages were located and tested, but installation failed on this guest. No further work is planned on that path, because Screen Sharing solves the problem well enough that improving the console experience has little value.

### 8.6 Unrelated noise in the logs

Two recurring log entries are unrelated to anything documented here and can be ignored or suppressed:

`org.clamav.clamd` fails to start every ten seconds with `Malformed database`, because the bundled virus definitions are long expired and cannot be refreshed. Unload the job if the log noise is a nuisance.

A `Podcast Composer` crash report appeared during the build. It is an ImageKit tooltip fault in a Server application that is not in use, and has no connection to remote administration or the display configuration.

### 8.7 Outstanding work

| # | Item | Priority | Status |
|---|---|---|---|
| 1 | Restore ipfw ruleset and reload the socket filter kext | High | Pending |
| 2 | Change any VNC password exposed in system.log | High | Pending |
| 3 | Take a clean snapshot of the working configuration | High | Pending |
| 4 | Install Chameleon to the system disk, removing the CD dependency | Medium | Not started |
| 5 | Apply persistent `ignore_msrs` to all candidate nodes | Medium | Pending |
| 6 | Delete the stale `unused0` RAW disk | Low | Pending |
| 7 | Correct `ostype` from `l26` to `other` | Low | Pending |
| 8 | Revisit resolution once Chameleon config is persistent | Low | Deferred |
| 9 | Test SMP operation with `cores: 2` | Low | Deferred |
| 10 | Document the service configuration | Low | Not started |

---

## 9. Startup checklist

Confirm before starting the VM:

| Layer | Item | Required value |
|---|---|---|
| Host | KVM `ignore_msrs` | Enabled on the node the VM will start on |
| VM | BIOS | SeaBIOS |
| VM | Machine type | pc-q35-2.5 |
| VM | CPU model | Penryn |
| VM | Memory | 4096 MB, ballooning disabled |
| VM | Display adapter | `vmware,memory=32`, never Cirrus |
| VM | Tablet | Disabled |
| VM | Network adapter | E1000 |
| VM | `args` line | AppleSMC, USB keyboard, USB mouse present |
| Storage | ide2 | Chameleon ISO attached |
| Storage | sata0 | 64 GB QCOW2 system disk |
| Boot | Firmware boot order | ide2 only |

---

## Appendix A: Approaches evaluated and rejected

This appendix records what was tried and did not work. Its purpose is to prevent the same options from being reconsidered from scratch, and to make clear which configuration choices are deliberate rather than arbitrary.

| Approach | Outcome |
|---|---|
| OVMF and LongQT OpenCore v0.7 with the installer as a CD-ROM | Installer never appeared in the picker |
| OVMF and LongQT OpenCore v0.7 with the installer as SATA | No improvement |
| LegacyOSXKVM Snow Leopard OpenCore image | Only OpenShell.efi was presented |
| SeaBIOS with OpenCore | Invalid combination; OpenCore requires EFI |
| Chameleon with default KVM MSR handling | Immediate reboot loop |
| Nehalem CPU model | Reset during Darwin kernel handoff |
| Two active vCPUs on 10.6.3 | Spinlock panic on CPU 1 |
| Chameleon attached as SATA optical media | Fatal SerialATAPI reset errors |
| USB keyboard on the first Q35 USB controller | Enumeration failure, no keyboard input |
| Adding a bare `-usb` argument | PCI slot collision, VM would not start |
| Proxmox tablet pointer enabled | USB enumeration stalls in the guest |
| QemuUSBTablet 1.1 and 1.2 packages | Installation failed on the guest |
| Cirrus display adapter after the 10.6.8 update | AppleVNCServer bus error on every frame |
| ARD kickstart flags, VNC legacy mode, manual password file | No effect; the fault was in the framebuffer, not access control |
| Chameleon `Graphics Mode` set to 1920x1080x32 | Did not take effect |

### A.1 OpenCore did not discover the installer

The initial approach used Q35 with OVMF firmware, LongQT OpenCore v0.7, a Nehalem CPU model, and the Snow Leopard ISO attached as a CD-ROM. OpenCore loaded correctly, but the picker offered only `Reset NVRAM` and `Toggle SIP`. The installer volume never appeared. Pressing Space to reveal auxiliary entries and moving the optical media to different controllers made no difference.

Converting the installer to a SATA hard disk, which later proved important under Chameleon, did not help OpenCore find it either. A Snow Leopard specific OpenCore image from the LegacyOSXKVM project was then tested and presented a different interface, but its only entry was `OpenShell.efi`.

The conclusion is that OpenCore, at least in the versions tested, is not a viable bootloader for a Snow Leopard Server installation of this vintage. The Apple Partition Map layout of the 10.6 installer is the most likely reason, since OpenCore's discovery logic is built around the GPT and EFI conventions of later releases.

One dead end is worth recording separately: OpenCore was at one point tested with SeaBIOS rather than OVMF, which produced only `Booting from Hard Disk...` and no picker at all. That was an invalid pairing rather than a meaningful test result. OpenCore requires an EFI environment, and SeaBIOS is correct only for Chameleon.

### A.2 The Chameleon reboot loop was a host problem, not a bootloader problem

After switching to SeaBIOS and Chameleon, the VM entered an immediate reboot loop during Chameleon startup. The ISO was verified as a valid El Torito bootable image, so the image itself was not at fault. Several Q35 machine versions were tried without effect.

The actual cause was KVM's default handling of unsupported model-specific register accesses. Enabling `ignore_msrs` on the host resolved the loop completely, after which Chameleon started normally and correctly enumerated `Mac OS X Server Install Disc`.

The lesson worth carrying forward is that a bootloader failing this early is at least as likely to be a host virtualisation problem as a guest configuration problem, and the host side is worth checking before working through machine type permutations.

### A.3 CPU model selection

With the CPU model set to Nehalem, Chameleon could start the installer, but the VM reset during the handoff to the Darwin kernel. Changing only the CPU model to Penryn, with every other parameter left alone, allowed the installer to proceed substantially further and ultimately to complete. Penryn is therefore the known-working model and should not be changed without a specific reason and a snapshot to fall back on.

### A.4 Installer media presentation

Presenting the installer as a SATA hard disk rather than as ATAPI optical media was necessary for Chameleon to find it reliably. Legacy Apple bootloaders are noticeably better at discovering Apple-partitioned volumes on disk devices than they are at driving emulated optical discovery. This is the reverse of the usual expectation, where installer media is attached as a CD-ROM, and it is easy to undo by accident during routine maintenance.

### A.5 AppleVNCServer crash loop after the 10.6.8 update

This is the most instructive failure in the build, because every visible symptom pointed at access control and the actual fault was in the framebuffer.

**Symptoms.** After the 10.6.8 Server combo update, Screen Sharing stopped working. SSH tunnels to port 5900 returned `Connection refused` most of the time. An `nmap` scan reported the port as `filtered`. Inside the guest, `netstat` showed a run of connections in `TIME_WAIT` with nothing `ESTABLISHED`, and the listening socket on 5900 appeared and disappeared. The system log showed:

```text
com.apple.launchd[1] (com.apple.AppleVNCServer[3544]): Job appears to have crashed: Bus error
com.apple.launchd[1] (com.apple.AppleVNCServer): Throttling respawn: Will start in 10 seconds
```

repeating roughly every seven seconds, with a corresponding crash report written to `/Library/Logs/DiagnosticReports/` each time.

**Time spent on the wrong causes.** Considerable effort went into ARD access control before the crash reports were read: repeated `kickstart` invocations with different privilege and user scopes, enabling VNC legacy mode, setting a VNC password through both supported and unsupported flag combinations, writing a password hash directly into `/Library/Preferences/com.apple.RemoteManagement.vncpasswd` with a `perl` one-liner, unloading and reloading launch daemons, and finally flushing the entire ipfw ruleset and unloading the application firewall kext. None of it had any effect, because a daemon that segfaults on startup cannot be configured into working.

**Diagnosis.** The crash report register state identified the fault precisely. The crashing thread was in `__memcpy`, with:

```text
rbx: 0x0000000000001000    4096 bytes  = 1024 px at 32 bpp
r15: 0x0000000000000800    2048 bytes  = 1024 px at 16 bpp
rcx: 0xfffffffffffff800    -2048       = the overrun
cr2: 0x0000000100680000    fault address, on a page boundary
```

`AppleVNCServer` was copying the framebuffer at 4096 bytes per scanline while the actual framebuffer rows were 2048 bytes, overrunning the mapped region by exactly 2048 bytes on every frame. `SIGBUS` rather than `SIGSEGV` confirmed this was an overrun off the end of a memory-mapped device region rather than a heap fault.

The guest configuration explained why:

```text
Pixel Depth: 16-Bit Color (ARGB1555)
Resolution:  1024 x 768
VRAM (Total): 1 MB
Vendor ID:   0x1013     (Cirrus Logic)
Device ID:   0x00b8     (GD 5446)
```

Apple's VNC server assumes a 32-bit framebuffer. The Cirrus adapter was providing a 16-bit one. The 1 MB of VRAM was a second, independent obstacle: a 32-bit 1024x768 framebuffer requires roughly 3 MB, so the depth could not have been raised on that adapter regardless.

**Resolution.** Changing the display adapter to `vmware,memory=32` and restarting the guest produced a 32-bit framebuffer, after which `AppleVNCServer` started cleanly and stayed running. No ARD configuration change was required beyond the standard activation.

**What to take from this.** The crash reports contained the answer from the first minute of the failure. Reading `/Library/Logs/DiagnosticReports/` before adjusting service configuration would have saved several hours. When a network service is intermittently reachable and then refuses connections, check whether the daemon is alive before investigating access control, firewalls, or tunnels.

---

## Appendix B: Symptom reference

| Symptom | Probable cause | Action |
|---|---|---|
| VM reboots repeatedly during Chameleon startup | `ignore_msrs` not set on the current host node | Apply the setting from section 3.1 to that node |
| VM resets during Darwin kernel boot | CPU model is not Penryn | Correct the CPU model |
| `panic(cpu 1 ...): Spinlock acquisition timed out` | SMP under Snow Leopard | Set `cores: 1`, or boot with `cpus=1` |
| Chameleon shows no bootable Apple volume | Installer attached as optical media, or missing from the VM | Attach the installer image as a SATA disk |
| Boot picker shows only `Booting from Hard Disk...` | OpenCore paired with SeaBIOS | Not a supported path; use Chameleon |
| No keyboard input at the Chameleon prompt or in the installer | Keyboard on the wrong USB controller | Confirm the keyboard is on `ehci-2.0`; verify topology per section 4.3 |
| `PCI: slot 29 function 7 not available for ich9-usb-ehci1` | A `-usb` flag was added to `args` | Remove it; Q35 provides the controllers already |
| `IOUSBFamily is having trouble enumerating a USB device`, long stalls | Proxmox tablet pointer enabled | Set `tablet: 0` |
| `SerialATAPI Terminating due to unrecoverable Reset error` | Chameleon attached as SATA optical media | Move the ISO to `ide2` |
| Installer appears frozen, ETA static for many minutes | Expected behaviour | Wait; check host-side CPU activity before intervening |
| `AppleVNCServer ... Job appears to have crashed: Bus error`, repeating | Framebuffer is not 32-bit | Set `--vga vmware,memory=32`; see Appendix A.5 |
| VNC refuses connections, port shows `filtered` to nmap | VNC server crashing on startup | Check `ps` and `/Library/Logs/DiagnosticReports/` before touching ARD config |
| Guest `netstat` shows only `TIME_WAIT` on 5900, never `ESTABLISHED` | Server accepting then dying | As above; this is a server fault, not a firewall fault |
| `launchctl list` shows no `com.apple.AppleVNCServer` job | ServerSetup launch daemon unloaded; ARDAgent owns the process | Expected. Check with `ps aux \| grep '[A]ppleVNCServer'` |
| SSH tunnel to 5900 times out | Forward target set to the guest's external address | Target `127.0.0.1`, not the translated address |
| `bind: Permission denied` on an SSH local forward | Local port below 1024 | Use a high-numbered local port |
| `system_profiler` reports no resolution or pixel depth | No OS X driver for VMware SVGA II | Expected and harmless; the VESA mode is still 32-bit |
| Chameleon `Graphics Mode` has no effect | Mode not in the adapter's VESA table, or config file not read from the ISO boot volume | See section 6.4 |
| `The current guest configuration does not support taking new snapshots` | RAW disks attached to the VM | Detach the installer disk; see section 8.2 |
| `org.clamav.clamd` respawning every 10 seconds | Expired virus definitions | Unrelated to anything here; unload the job |

---

## Appendix C: Command reference

Host, KVM MSR handling:

```bash
echo 1 > /sys/module/kvm/parameters/ignore_msrs
cat /sys/module/kvm/parameters/ignore_msrs
echo "options kvm ignore_msrs=Y" > /etc/modprobe.d/kvm.conf
update-initramfs -k all -u
```

Host, VM inspection and configuration:

```bash
qm config 143
qm monitor 143
qm set 143 --vga vmware,memory=32

sha1sum MAC_OS_X_10-6-3_SNOW_LEOPARD_SERVER.ISO

qemu-img convert -p -f raw -O qcow2 \
  /var/lib/vz/template/iso/MAC_OS_X_10-6-3_SNOW_LEOPARD_SERVER.ISO \
  /tmp/SnowLeopardServer-Installer.qcow2

qm disk import 143 /tmp/SnowLeopardServer-Installer.qcow2 NFS-STORE --format qcow2
```

Chameleon boot arguments (installation and single-CPU boots):

```text
cpus=1 -v
```

Guest, system verification:

```bash
sw_vers
uname -a
sysctl hw.ncpu
system_profiler SPDisplaysDataType
```

Guest, enable Apple Remote Management for a named user:

```bash
sudo /System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart \
  -activate -configure -access -on -users adminuser -privs -all -restart -agent -console
```

Guest, verify the VNC server is alive:

```bash
ps aux | grep '[A]ppleVNCServer'
netstat -an | grep 5900
ls -lt /Library/Logs/DiagnosticReports/ | head -5
syslog -k Sender AppleVNCServer | tail -n 50
```

Guest, firewall state:

```bash
sudo ipfw list
```

Workstation, shell and tunnelled Screen Sharing:

```bash
ssh -p 2222 adminuser@server.example.lan
ssh -p 2222 -L 5901:127.0.0.1:5900 adminuser@server.example.lan
```

Then connect to `vnc://localhost:5901`.
