Running Ubuntu ARM Virtual Machines on macOS with QEMU + SSH Access

DevOps & Cloud Engineer — building scalable, automated, and intelligent systems. Developer of sorts | Automator | Innovator
Search for a command to run...

DevOps & Cloud Engineer — building scalable, automated, and intelligent systems. Developer of sorts | Automator | Innovator
Artificial Intelligence has become one of the biggest talking points in software engineering. Every week, a new tool promises to automate deployments, fix production incidents, or replace developers a

You spin up a Kubernetes workload. You connect to PostgreSQL. You add sslmode=require because security matters. And then PostgreSQL replies with: server does not support SSL, but SSL was required Wai

When you first approach Tencent Cloud, it feels familiar if you come from AWS or Azure. There are VPCs, Kubernetes clusters, load balancers, object storage, IAM, everything you would expect. But once

When I first automated Docker builds and deployments, I thought the hard part would be writing the YAML. It was not. The real challenges were versioning, preventing accidental rollbacks, handling envi

For a long time, Docker Compose felt like the perfect solution. Simple YAML, fast local setup, predictable behavior. For a single service or even a small stack, it works beautifully. But at some point, reality catches up. As the application grew, tra...

CodeOps Studies
40 posts
Simple write-ups on day to day code or devops experiments, tests etc.
When using an Apple Silicon Mac, running virtual machines can be tricky, especially when you want a full Linux environment with working networking and SSH access. Fortunately, QEMU, combined with macOS’s lightweight HVF (Hypervisor Framework) acceleration, makes this possible and surprisingly smooth.
In this guide, we will:
Set up QEMU for ARM virtualization
Create and install Ubuntu on a raw disk image
Run the VM with proper hardware configs
Fix SSH networking when the VM initially has no external access
Successfully SSH into the VM via port forwarding
QEMU isn’t just an emulator on Apple Silicon, it can use Apple’s HVF (Hypervisor Framework) for near-native virtualization performance.
And unlike GUI tools, QEMU gives you full control over networking which is important when you want SSH and cluster communication.
Make sure QEMU is installed:
brew install qemu
This includes:
QEMU binaries (qemu-system-*)
Virtual device drivers
UEFI firmware for ARM
Also download:
Ubuntu ARM Server ISO (ubuntu-24.04.3-live-server-arm64.iso)
UEFI firmware for ARM (QEMU_EFI.fd) — usually packaged inside QEMU:
find /opt/homebrew -name QEMU_EFI.fd
We will create a 15GB raw disk:
qemu-img create -f raw ubuntu-latest.raw 15G
This will act as your VM’s virtual hard drive.
Boot with installation ISO:
qemu-system-aarch64 \
-monitor stdio \
-M virt,highmem=off \
-accel hvf \
-cpu host \
-smp 4 \
-m 3000 \
-bios /path/to/QEMU_EFI.fd \
-device virtio-gpu-pci \
-display default,show-cursor=on \
-device qemu-xhci \
-device usb-kbd \
-device usb-tablet \
-device intel-hda \
-device hda-duplex \
-drive file=ubuntu-latest.raw,format=raw,if=virtio,cache=writethrough \
-cdrom ubuntu-24.04.3-live-server-arm64.iso
Then proceed through the installer normally, and enable OpenSSH Server when prompted.
After installation, shutdown the VM.
You may try running the VM normally first:
qemu-system-aarch64 \
-monitor stdio \
-M virt,highmem=off \
-accel hvf \
-cpu host \
-smp 4 \
-m 3000 \
-bios /path/to/QEMU_EFI.fd \
-device virtio-gpu-pci \
-display default \
-device qemu-xhci \
-device usb-kbd \
-device usb-tablet \
-device intel-hda \
-device hda-duplex \
-drive file=ubuntu-latest.raw,format=raw,if=virtio,cache=writethrough
Inside the VM, check your IP:
ip a
You'll likely see:
10.0.2.15
This means NAT networking is enabled, but SSH access from host → guest is not yet exposed.
We restart QEMU with networking flags:
qemu-system-aarch64 \
-monitor stdio \
-M virt,highmem=off \
-accel hvf \
-cpu host \
-smp 4 \
-m 3000 \
-bios /path/to/QEMU_EFI.fd \
-drive file=ubuntu-latest.raw,format=raw,if=virtio,cache=writethrough \
-netdev user,id=net0,hostfwd=tcp::2222-:22 \
-device virtio-net-pci,netdev=net0
Now SSH should work through port 2222:
ssh -p 2222 username@127.0.0.1
But wait… sometimes it doesn’t. Instead, you may see:
kex_exchange_identification: read: Connection reset by peer
This means the VM’s network interface is not configured correctly.
Inside the VM:
ls /etc/netplan
You will see something like:
50-cloud-init.yaml
Edit it:
sudo nano /etc/netplan/50-cloud-init.yaml
Replace contents with:
network:
version: 2
ethernets:
ens3:
dhcp4: true
Apply changes:
sudo netplan apply
Your network now comes up correctly.
From macOS:
ssh -p 2222 <your-username>@127.0.0.1
Success!
I needed ssh to work because it was not directly possible to share the clipboard between my machine (macOS) and the Qemu VM.
| Task | Command / Result |
| Create VM Disk | qemu-img create -f raw ubuntu.raw 15G |
| Install Ubuntu | QEMU boot with ISO |
| Run VM | QEMU run with virtio-net-pci |
| Fix Networking | Edit /etc/netplan/*.yaml and set ens3 |
| SSH into VM | ssh -p 2222 user@127.0.0.1 |
This setup provides:
Native-speed ARM virtualization on macOS
A clean, reproducible Ubuntu VM workflow
SSH access that works reliably
Ready environment for Kubernetes nodes, labs, or development clusters