A simple Node.js-based launcher for a preconfigured QEMU virtual machine. VPN routing is handled by your host VPN client or network setup.
⚠️ This project does not include QEMU binaries due to licensing. See the QEMU Setup section below for instructions on installing them manually.
- Launches a QEMU VM from a preconfigured disk image
- Optional ISO boot for OS installs
- Config-driven VM settings (CPU, RAM, display, accel)
- Designed to run alongside a host VPN (routing handled externally)
- Windows Hypervisor Platform or Hyper-V enabled (for WHPX acceleration)
- Node.js (v18+ recommended for development/build)
- QEMU binaries in
qemu/ - VM disk image (e.g.,
.qcow2) - Optional ISO image for installs
pkgfor building the Windows EXE- Optional VPN client (OpenVPN or WireGuard) if you want host VPN routing
When exporting and distributing, the directory must have:
deb.img(or your VM disk image)qemu/config.json- ISO file specified by
config.json(for installs)
The launcher reads config.json and uses these keys:
showConsole: Show QEMU output window.useIso:trueto boot from ISO for installs.isoPath: Path to the installer ISO.diskPath: Path to the VM disk image.memoryMB: RAM in MB.cpus: vCPU count.diskFormat: Disk format, defaultqcow2.compatMode:trueto use legacy devices (IDE disk, RTL8139 NIC, standard VGA). Helpful if WHPX has MSI/virtio issues.videoDevice: Explicit QEMU video device. Set this tovirtio-vgato avoid falling back to Bochs/standard VGA while keeping other compatibility settings unchanged.machine: QEMU machine type, defaultpc(i440fx).display: Display backend, defaultsdl(often smoother thangtkon Windows).accel: Acceleration backend, defaultwhpx. You can add options likewhpx,kernel-irqchip=offif WHPX MSI injection fails.cpu: CPU model, defaultmax(WHPX does not accepthost).hostForwards: Array of explicit QEMUhostfwdrules. Bind these to127.0.0.1if the service should stay local to the Windows host. On the default QEMU user network, omitguestAddressand let QEMU target the default guest automatically.vnc: Optional local-only VNC console settings.127.0.0.1:1maps to TCP port5901.tray: Optional Windows tray settings. Whenenabledistrue,amino launchstarts QEMU headless, hides the taskbar window, and keeps control in a native tray icon.
Paths in config.json can be relative to the project root or absolute.
This project depends on QEMU to launch virtual machines. Due to licensing terms (GPLv2), QEMU binaries are not included in this repository.
Download QEMU for Windows from:
Extract the .exe and .dll files into the qemu/ directory at the root of this project.
If you need a minimal Debian installation image, download the official Debian netinst ISO:
Place the .iso file wherever you keep VM assets and set isoPath in config.json to match.
Example:
vm-images/
├── debian-13.3.0-amd64-netinst.iso
├── debian.qcow2
The main AminoVM command surface is:
amino launch [--headless] [--tray] [--window]
amino stop
amino status
amino ports list
amino ports add --host 127.0.0.1 --hport 8080 --gport 9092
amino ports remove --host 127.0.0.1 --hport 8080
amino disk resize --path deb.img --size 80G
amino image list
amino image select --path deb.img
amino image install --path some.iso
amino build windows
amino build linux
amino build macosOn Windows, --tray now launches QEMU headless and keeps the VM in a native tray icon. Use --window to force the normal QEMU window even when tray.enabled is set in config.json.
Install dependencies:
npm installInstall a distro (recommended flow):
- Set
useIsototrueinconfig.jsonand pointisoPathto the ISO. - Run:
node index.js launch- After installation, set
useIsoback tofalseto boot from disk.
Legacy install script (uses hardcoded paths):
node install.jsRun/test an existing image:
node index.js launchWhen you add forwards on the default slirp network, leave guestAddress unset unless you intentionally changed the guest IP.
Example local-only forwards for a browser/reverse-proxy workflow:
"hostForwards": [
{ "protocol": "tcp", "hostAddress": "127.0.0.1", "hostPort": 443, "guestPort": 443 },
{ "protocol": "tcp", "hostAddress": "127.0.0.1", "hostPort": 9090, "guestPort": 9090 },
{ "protocol": "tcp", "hostAddress": "127.0.0.1", "hostPort": 2222, "guestPort": 22 }
],
"videoDevice": "virtio-vga",
"vnc": { "enabled": true, "address": "127.0.0.1", "display": 1 },
"tray": { "enabled": true, "tooltip": "AminoVM", "cockpitUrl": "https://127.0.0.1:9090" }If the Debian guest still tries to start an old OpenVPN unit you no longer use, run this inside the guest:
sudo systemctl disable --now openvpn-client@work.service; sudo rm -f /etc/systemd/system/multi-user.target.wants/openvpn-client@work.service; sudo systemctl reset-failed openvpn-client@work.serviceThat removes the stale boot dependency and clears the failed state from Cockpit.
Your VM disk capacity is defined by the image file (deb.img). If the guest is running out of space, do this:
- Stop the VM completely.
- Check current image size:
npm run disk:info- Increase image capacity (example: add 20 GiB):
npm run disk:grow -- --add 20G- Alternative (set exact total size):
npm run disk:grow -- --size 40GNotes:
disk:growcreates a backup inimgbackup/by default.- Use
--no-backuponly if you already have a backup and want a faster run. - This only grows the image container. You must expand the partition/filesystem inside Debian.
Install tools:
sudo apt-get update
sudo apt-get install -y cloud-guest-utilsIdentify your root disk and partition layout:
lsblk -o NAME,SIZE,FSTYPE,TYPE,MOUNTPOINT
findmnt -no SOURCE,FSTYPE /Common cases:
- Non-LVM root partition (ext4), e.g.
/dev/sda1or/dev/vda1:
sudo growpart /dev/sda 1
sudo resize2fs /dev/sda1If your disk is virtio (compatMode: false), use /dev/vda + partition number instead.
- LVM root (common Debian guided install):
sudo growpart /dev/sda 3
sudo pvresize /dev/sda3
sudo lvextend -l +100%FREE "$(findmnt -no SOURCE /)"
sudo resize2fs "$(findmnt -no SOURCE /)"If your root filesystem is XFS instead of ext4, use:
sudo xfs_growfs /Verify free space:
df -h /Old:
npm build = pkg . --targets node14-win-x64 --output aminovm.exe --debug
npx pkg . --targets node14-win-x64 --output aminovm.exe --debug --win-console=falseNew:
npm run build
npm run build:linux
npm run build:macos