ARM64 VM on macOS with libvirt + QEMU

This is the same article I published last year, except updated for M1 Macs. Overall, this method is great for headless Linux VMs that run in the background. We will be using the ARM versions of libvirt and QEMU, with full Hypervisor.Framework support.
Installing libvirt and QEMU
- First, install homebrew, which is a package manager for macOS.
- Run
brew install qemu gcc libvirt. - Since macOS doesn't support QEMU security features, we need to disable them:
echo 'security_driver = "none"' >> /opt/homebrew/etc/libvirt/qemu.conf echo "dynamic_ownership = 0" >> /opt/homebrew/etc/libvirt/qemu.conf echo "remember_owner = 0" >> /opt/homebrew/etc/libvirt/qemu.conf - Finally start the libvirt service, with
brew services start libvirt. It will start after boot as well.
Installing Ubuntu Server 20.04 for ARM
There are two ways to access the virtual display of the VM, either using a VNC client or the virt-viewer program. I recommend RealVNC Viewer. The VNC client is responsive and quick to install, but if you have multiple VMs you need to manually manage the different ports. The rest of this guide uses VNC.
-
Create a
vmsfolder in your home directory, and generate a disk image. Change50gto the size of your prefered disk:mkdir ~/vms && cd ~/vms qemu-img create -f qcow2 ubuntu.qcow2 50g -
Download the ARM Ubuntu Server 20.04 Install Image and my ARM libvirt XML template and place the .iso and .xml files in the same folder. (macOS <= 12.3 needs an older XML template).
-
Modify the following elements in the
ubuntu.xmlfile to match your your VM preferences and file paths. Save, then runvirsh define ubuntu.xmlfollowed byvirsh start ubuntu.<domain type='qemu' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'> <name>name of the VM</name> <memory unit='GB'>how much ram</memory> <vcpu>how many cpus</vcpu> ... <disk type='file' device='disk'> <source file='full path to your qcow2 file'/> ... <disk type='file' device='disk'> <source file='full path to your install iso'/> -
Start RealVNC Viewer and connect to
localhost. If you don't see the installation screen, or possibly reinstalling, click theCtrl+Alt+Delbutton to reboot the machine, and quickly pressEscto get into the OVMF menu. Select Boot Manager, then boot the install image. For me it wasUEFI Misc Device 3.

-
Install Ubuntu Server normally, making sure to enable the SSH server. Once it restarts you can connect to the VM from your terminal by running
ssh -p 2222 user@localhost. -
To send a shutdown signal to your VM, run
virsh shutdown ubuntu. To force shutdown, runvirsh destroy ubuntu. -
To forward a port, e.g. port 443 from the VM to port 8443 locally, run the following:
ssh -p 2222 -L8443:localhost:443 user@localhost
Multiple VMs
If you want to create multiple VMs, create an XML file for each machine with a unique UUID, VM name, and VNC port. Also, change the hostfwd argument so that each VM exposes a different port for SSH, e.g. 2223 instead of 2222. After you have defined them all, you can get a list of the VMs that are currently running with virsh list.
Troubleshooting
Newer versions of Ubuntu Server may require disabling the irqbalance service in order to gracefully shutdown:
sudo systemctl disable irqbalance
For those on Big Sur, you will require the rpcgen dependency for compilation. To satisfy this, download a previous rpcgen build and install with brew install rpcgen.rb && brew pin rpcgen. Then, download the latest libvirt.rb, edit out the offending rpcgen lines, and install with brew install libvirt.rb. Also the last version of qemu compatible with macOS 11 and 12 is qemu 9.0.2. Important: IPv6 must be disabled in order to allow the internal DNS server to respond!
References:
- Grasping Tech: Creating a Ubuntu Desktop 18.04 Virtual Machine on macOS with QEMU
- Homebrew Discussion: Failed to connect socket to '/var/run/libvirt/libvirt-sock'
- StackExchange: libvirt on Apple Silicon
- GitLab Issue: libvirt doesn't work with apple silicon
Update June 2023: Added troubleshooting section. Aug 2024: Added notes on compiling on Big Sur