This guide has two parts: first, setting up QEMU with KVM acceleration on your host machine. Second, creating and configuring Arch Linux VM images for testing audio applications.
I use QEMU because it's fast with KVM and trivial to run from the command line — no GUI, no complexity, just scriptable VMs.
Table of Contents #
- Installation and setting up QEMU
- Creating Arch Linux VM for Audio E2E Testing
- Quick QEMU Command Reference
Installation and setting up QEMU #
Install QEMU:
sudo pacman -S qemu-full1. CPU support — check with:
LC_ALL=C lscpu | grep -i virtualization
# Should show: VT-x (Intel) or AMD-V (AMD)2. Kernel modules — load and persist:
sudo modprobe kvm
sudo modprobe kvm_intel # Intel
# OR
sudo modprobe kvm_amd # AMD
# Persist after reboot:
echo "kvm" | sudo tee /etc/modules-load.d/kvm.conf
echo "kvm_amd" | sudo tee -a /etc/modules-load.d/kvm.conf # for AMD
#echo "kvm_intel" | sudo tee -a /etc/modules-load.d/kvm.conf # adjust for INTEL3. User permissions — add yourself to the group:
sudo usermod -aG kvm $USER
# Log out and back in for group to apply4. Verify it works:
ls -la /dev/kvm # Should exist and be owned by kvm group
qemu-system-x86_64 -accel kvm -hda /dev/null # Should start without "falling back to tcg" warningCreating Arch Linux VM for Audio E2E Testing #
1. Create Base Disk Image #
qemu-img create -f qcow2 arch-base.qcow2 10GDownload the Arch ISO (check archlinux.org/download for current version):
# HTTP download from geo mirror
curl -O https://geo.mirror.pkgbuild.com/iso/latest/archlinux-x86_64.iso
# OR use BitTorrent (recommended by Arch, helps reduce mirror load):
# curl -O https://archlinux.org/releng/releases/latest/torrent/
# Then open the .torrent file with your client (transmission, qbittorrent, etc.)Verify the ISO signature (optional but recommended):
# Download signature and checksums
curl -O https://geo.mirror.pkgbuild.com/iso/latest/sha256sums.txt
curl -O https://geo.mirror.pkgbuild.com/iso/latest/sha256sums.txt.sig
# Verify checksum matches
sha256sum -c sha256sums.txt --ignore-missing
# Verify PGP signature (requires archlinux-keyring installed)
gpg --verify sha256sums.txt.sig sha256sums.txt2. Boot the ISO and Install Arch #
Start the VM with the ISO mounted for installation:
qemu-system-x86_64 \
-accel kvm \
-m 2G \
-cdrom archlinux-x86_64.iso \
-hda arch-base.qcow2 \
-boot dThis opens a normal window where you can run through the Arch installer. Follow the Arch installation guide with these choices:
| # | Setting | Selection | Notes |
|---|---|---|---|
| 0 | Disk | 10GB btrfs | zstd compression, flat layout (no subvolumes), skip LVM |
| 1 | Swap | Skip | 2GB RAM is sufficient |
| 2 | Bootloader | Limine | Modern, handles btrfs natively |
| 3 | Kernel | Standard linux | Not LTS or Zen |
| 4 | User | pr / pr | Create user pr with password pr |
| 5 | Profile | Minimal | No desktop environment needed |
| 6 | Network | Copy ISO configuration | systemd-networkd with DHCP |
| 7 | Audio | PipeWire | Enable PipeWire user services after first boot |
| 8 | Firewall | UFW | Disable it in post install; VM is NAT isolated |
Additional packages to install:
# Base system
base base-devel linux linux-firmware
# Testing essentials
openssh neovim curl git wget btop jq zip unzip alsa-utils libpulse pulsemixer openssh3. Post Install Configuration #
Before freezing the base image, configure the system for automated testing. Boot the newly installed system (not the ISO) and run:
qemu-system-x86_64 -accel kvm \
-m 2G \
-hda arch-base.qcow2 \
-audiodev pa,id=snd0 \
-device intel-hda \
-device hda-duplex,audiodev=snd0 \
-nic user,hostfwd=tcp::2222-:22- Enable SSH server
sudo systemctl enable --now sshd- Disable Firewall
sudo ufw disablesystemctl enable serial-getty@ttyS0.service- Optional: passwordless sudo for automated testing
echo "pr ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/pr- Verify audio is working
pactl info | grep "Server Name" # Should show "PulseAudio (on PipeWire)"
# Enable PipeWire if it's not working
# systemctl --user enable --now pipewire pipewire-pulse wireplumber- Reduce bootloader timeout (Limine)
Edit the Limine configuration to speed up boot:
sudo sed -i 's/timeout:.*/timeout: 0/' /boot/limine/limine.conf- Power off to freeze the base image
poweroff4. Freeze Base Image and Create Test Snapshot #
After configuration, shut down and protect the base image from accidental writes. QCOW2 snapshots reference specific block offsets in the backing file — modifying the base after creating snapshots corrupts the chain.
chmod 444 arch-base.qcow2Create a derived snapshot for testing:
qemu-img create -f qcow2 -F qcow2 -b arch-base.qcow2 arch-snapshot.qcow25. Launch for Testing #
Testing runs headless with SSH access. Start the VM without display and connect via forwarded port:
# Start the VM headless
qemu-system-x86_64 -accel kvm -m 2G -hda arch-snapshot.qcow2 \
-audiodev pa,id=snd0 -device intel-hda -device hda-duplex,audiodev=snd0 \
-display none -serial stdio \
-nic user,hostfwd=tcp::2222-:22
# From another terminal, SSH into the VM
ssh -p 2222 pr@localhostThe serial console (-serial stdio) shows kernel messages and boot progress. Once booted, use SSH for interactive work.
Resetting Test State #
Snapshots are copy-on-write. To reset to clean state, delete and recreate:
rm arch-snapshot.qcow2
qemu-img create -f qcow2 -F qcow2 -b arch-base.qcow2 arch-snapshot.qcow2Quick QEMU Command Reference #
Once you have a working VM image, here's a quick template to launch it headless with audio and SSH support:
qemu-system-x86_64 \
-accel kvm \
-m 2G \
-hda arch-snapshot.qcow2 \
-audiodev pa,id=snd0 \ # PulseAudio backend
-device intel-hda -device hda-duplex,audiodev=snd0 \ # Audio device
-display none \ # No GUI
-serial stdio \ # Serial console for boot logs
-nic user,hostfwd=tcp::2222-:22 # SSH on port 2222Connect via SSH: ssh -p 2222 pr@localhost
The -accel kvm flag is what makes it fast. Without it, QEMU silently falls back to TCG.
Published