Skip to content

Instantly share code, notes, and snippets.

@gsf
Last active November 9, 2024 03:35
Show Gist options
  • Save gsf/c7bb24178700ffcaeab9c100c63264bb to your computer and use it in GitHub Desktop.
Save gsf/c7bb24178700ffcaeab9c100c63264bb to your computer and use it in GitHub Desktop.
Ubuntu VM on macOS with QEMU

Ubuntu VM on macOS with QEMU

For work I have an Intel Core i5 MacBook. With the Docker Desktop license changes I looked into minikube and Multipass but both failed when I got on our VPN with Cisco AnyConnect due to bridged networking in hyperkit (see links at bottom).

I realized I would be happy SSHing into a local Linux VM but passed on VirtualBox to avoid depending on legacy system extensions. I landed on libvirt for the VM, then realized I could remove libvirt from the equation to finally end up at this quick, simple setup for an Ubuntu VM on macOS with QEMU.

First, install QEMU (see https://wiki.qemu.org/Hosts/Mac for other options):

brew install qemu

Now create the file that will serve as the hard drive for the VM:

qemu-img create -f qcow2 ubuntu.qcow2 50g

Download an Ubuntu ISO file (or any other linux):

curl -LO https://releases.ubuntu.com/20.04/ubuntu-20.04.3-live-server-amd64.iso

Next, run this command to boot the VM (I put this in a script I call boot.sh):

qemu-system-x86_64 \
  -cdrom "ubuntu-20.04.3-live-server-amd64.iso" \
  -hda "ubuntu.qcow2" \
  -machine "type=q35,accel=hvf" \
  -m "4G" \
  -netdev "user,id=n1,hostfwd=tcp::2222-:22" \
  -device "virtio-net-pci,netdev=n1,bus=pcie.0,addr=0x19"

Explanation of options (many of these are lifted from https://www.arthurkoziel.com/qemu-ubuntu-20-04/):

  • -cdrom boots the VM from the ISO file for installation. Drop it on subsequent boots once Ubuntu is installed.
  • -hda specifies the hard drive file we'll be using.
  • -machine uses the latest machine type and the macOS native hypervisor
  • -m is the max amount of memory the machine may use
  • -netdev and -device set up networking so we can ssh into the VM on port 2222

This command will open a QEMU window you can Alt-Tab to in order to monitor machine startup and proceed with installation. That window also has a handy "Power Down" dropdown option in the "Machine" item in the menu bar.

Screen Shot 2022-02-11 at 12 33 46 PM

Once installation is done I add the contents of my public SSH key to ~/.ssh/authorized_keys in the VM, then ssh in with the following (starting or attaching to a screen session on login):

ssh -i ~/.ssh/gsf_id_ed25519 -p 2222 -t localhost 'screen -D -R'

I also need to share directories between host and guest, but Plan 9 and virtfs are not available in QEMU on macOS(see update below!), so I use sshfs (IP address of host is 10.0.2.2):

sshfs 10.0.2.2:/Users/gsf/Downloads ~/Downloads

That command will set that ~/Downloads mount until the next boot. To make it automatic, I generate an SSH keypair on the guest, add the public key to authorized_keys on the host, and make the sshfs mount on boot by adding the following to /etc/fstab:

sshfs#[email protected]:/Users/gsf/Downloads /home/gsf/Downloads fuse _netdev,allow_other,uid=1000,gid=1000,idmap=user,identityfile=/home/gsf/.ssh/id_ed25519 0 0

That's it! I kept notes on discoveries along the way below.

Notes

Multipass and minikube use hyperkit, which sets up bridged networking. This is what clashes with the AnyConnect client:

I'm still on an Intel MacBook but looking for a solution that I can continue using on an M1 processor. That rules out xhyve: machyve/xhyve#218

This was also helpful in laying out steps for running Ubuntu with QEMU on macOS: https://graspingtech.com/ubuntu-desktop-18.04-virtual-machine-macos-qemu/

@hedges333
Copy link

When I tried to copy files from the guest fs to the 9p-mounted fs from the host, it said that there was not enough space available on the drive. I used the file manager GUI in LXDE on Debian Bullseye.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment