8.5 KiB
Testing NaxOS on macOS
This guide provides step-by-step instructions for testing and running the complete NaxOS appliance on macOS. It covers full live virtual machine testing with QEMU, rapid local frontend/API development, and headless automated verification.
Testing Methods Overview
| Method | Target Use Case | Requirements |
|---|---|---|
| Method 1: Full Live QEMU VM | Complete appliance test: Linux 6.18 kernel, real OpenZFS pool tank, live naxos-api daemon, and naxos-ui web interface. |
qemu-system-x86_64 (Homebrew or Nix) |
| Method 2: Local UI / API Dev | Rapid UI development, styling iteration, and component testing on macOS without a VM. | Node.js 20+, npm |
| Method 3: Headless Verification | Automated end-to-end browser capture and visual validation. | Python 3 + Playwright or Chromium |
Method 1: Full Appliance VM Testing via QEMU
This method boots the actual NaxOS NixOS 26.05 operating system with Linux kernel 6.18, creates a virtual target disk, provisions a real OpenZFS pool (tank), and runs the full API daemon and Web UI with port forwarding to macOS.
1. Prerequisites
Install QEMU on macOS using Homebrew (or via Nix):
# Using Homebrew
brew install qemu
# Or if you use Nix on macOS:
nix-shell -p qemu
Verify that qemu-system-x86_64 is available:
qemu-system-x86_64 --version
Note
Apple Silicon (M1/M2/M3/M4) Note: When running
qemu-system-x86_64on Apple Silicon Macs, QEMU uses TCG (Tiny Code Generator) software emulation. Because it is emulating x86_64 on ARM64, boot times will take approximately 15–30 seconds.
2. Download the NaxOS Installation Media
Download the official bootable ISO from the Gitea package registry:
curl -fSL -o /tmp/naxos-installer.iso \
"https://git.lholz.de/api/packages/naxos/generic/naxos-installer-iso/1.0.0/naxos-installer-x86_64-linux.iso"
3. Prepare Boot Artifacts & Virtual Drive
Extract the direct-boot kernel and initrd from the ISO (or boot directly from the ISO cdrom):
# Create a 20 GB QCOW2 virtual drive for OpenZFS testing
qemu-img create -f qcow2 /tmp/naxos-target-disk.qcow2 20G
# Mount or extract the ISO to retrieve the kernel and initrd
mkdir -p /tmp/naxos-iso-mnt /tmp/naxos-boot
hdiutil attach -nobrowse -readonly -mountpoint /tmp/naxos-iso-mnt /tmp/naxos-installer.iso
cp -R /tmp/naxos-iso-mnt/boot /tmp/naxos-boot/
hdiutil detach /tmp/naxos-iso-mnt
Find the extracted kernel and initrd paths:
KERNEL=$(find /tmp/naxos-boot -name bzImage | head -n 1)
INITRD=$(find /tmp/naxos-boot -name initrd | head -n 1)
echo "Kernel: $KERNEL"
echo "Initrd: $INITRD"
4. Launch the NaxOS Virtual Appliance
Start QEMU with:
- RAM: 2048 MB (2 GB)
- CPU: 2 cores (
-smp 2) - Storage: VirtIO disk attached to
/tmp/naxos-target-disk.qcow2(appears as/dev/vdain the VM) - Networking: User-mode networking with port forwarding:
- Host port
18080-> VM port80(NaxOS Web UI) - Host port
18443-> VM port8443(NaxOS HTTPS / API)
- Host port
- Serial Console: Stdio redirected to your terminal for real-time kernel and shell access.
qemu-system-x86_64 \
-m 2048 \
-smp 2 \
-kernel "$KERNEL" \
-initrd "$INITRD" \
-append "init=/nix/store/*-nixos-system-nixos-*/init console=ttyS0,115200n8 loglevel=6" \
-drive file=/tmp/naxos-target-disk.qcow2,if=virtio,format=qcow2 \
-net nic,model=virtio \
-net user,hostfwd=tcp::18443-:8443,hostfwd=tcp::18080-:80 \
-nographic
Once booted, press Enter to get the root prompt:
<<< Welcome to NixOS 26.05! >>>
[root@nixos:~]#
5. Initialize the OpenZFS Storage Pool in the VM
Inside the VM terminal, create the real OpenZFS pool tank on the virtual drive /dev/vda:
# Create OpenZFS pool
zpool create tank /dev/vda -f
# Create standard appliance datasets
zfs create tank/media
zfs create tank/backup
zfs create tank/container
# Verify pool health and status
zpool status
zpool list
zfs list
You should see:
NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT
tank 19.5G 832K 19.5G - - 0% 0% 1.00x ONLINE -
6. Verify Real System Metrics & Declarative Rebuild
The NaxOS Management Daemon (naxos-api) queries real kernel interfaces rather than mocked data:
- ZFS ARC Cache:
/proc/spl/kstat/zfs/arcstats - Uptime:
/proc/uptime - Memory:
os.totalmem()andos.freemem() - Disk I/O:
/proc/diskstats - Journal Logs: Real
journalctl -n 100 -o json --no-pager
Test the API daemon endpoints from inside the VM or from macOS:
# Check system metrics from your Mac:
curl http://localhost:18443/api/v1/system/metrics
# Check real ZFS pools:
curl http://localhost:18443/api/v1/storage/pools
# Check active system services:
curl http://localhost:18443/api/v1/system/services
Testing "Apply Changes" (Live SSE Stream)
Trigger a declarative system rebuild from macOS:
curl -N -X POST http://localhost:18443/api/v1/system/rebuild
You will receive real Server-Sent Events (SSE) streaming live steps:
validating- Synthesizing declarative NixOS configuration.building- Executing/run/current-system/sw/bin/nixos-rebuild dry-activate.reloading- Applying dataset quotas and reloading Samba shares.completed- Generation activated successfully.
7. Accessing the Web Dashboard
Open your web browser on macOS and navigate to:
http://localhost:18080
You will see:
- Glassmorphism Appliance Dashboard: Live storage capacity, real ARC hit ratio (100%), ARC cache size, CPU and memory gauges.
- Storage Management: Visual hierarchy of pool
tank, datasets (media,backup,container), and snapshots. - App Store: Curated 1-click catalog (Immich, Jellyfin, Nextcloud, Vaultwarden).
- Apply Changes Modal: Interactive rebuild viewer streaming real systemd activation logs.
8. Clean VM Shutdown
To cleanly unmount OpenZFS datasets, export the storage pool, and power down the virtual machine, execute inside the VM console:
poweroff
Or press Ctrl+A then X to exit QEMU immediately.
Method 2: Local UI & API Rapid Development
To develop or preview the Web UI directly on macOS without launching QEMU:
1. Build and Run the Web UI
cd naxos-ui
# Install dependencies
npm install
# Start Vite development server
npm run dev
Open http://localhost:5173 in your browser.
2. Previewing the Production SPA Build
cd naxos-ui
npm run build
npm run preview -- --port 3000
Open http://localhost:3000 to inspect the production asset bundle.
3. Running the Management Daemon Locally (Mock Fallback)
If running naxos-api on macOS outside of Linux, it automatically falls back gracefully when Linux-specific paths (/proc/spl/kstat/zfs/arcstats, zpool) are unavailable:
cd naxos-api
npm install
npm run build
npm start
The API daemon listens on http://localhost:8088.
Method 3: Headless Automated Browser Verification
To run headless end-to-end tests or re-generate screenshots automatically:
# Using Python Playwright
python3 -m pip install playwright
python3 -m playwright install chromium
# Run headless screenshot verification
python3 - << 'EOF'
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page(viewport={"width": 1440, "height": 900})
page.goto("http://localhost:18080")
page.wait_for_selector("text=System Healthy")
page.screenshot(path="test-overview.png")
print("Screenshot captured successfully!")
browser.close()
EOF
Troubleshooting & FAQ
Port 18080 or 18443 is already in use
Check which process is listening on the port:
lsof -i :18080
lsof -i :18443
Kill the stale process or change the -net user,hostfwd=tcp::18080-:80 parameter in the QEMU launch command to an alternate port (e.g. hostfwd=tcp::28080-:80).
Strict MIME Type Errors (Failed to load module script)
Browsers enforce strict MIME checking for ES modules (Content-Type: text/javascript; charset=utf-8). If serving files via Python or custom static servers, ensure MIME types are explicitly configured:
import mimetypes
mimetypes.add_type('application/javascript', '.js')
mimetypes.add_type('text/css', '.css')
The standard naxos-api and production nginx containers already include appropriate MIME headers out of the box.