Featured

Run Ubuntu VMs with Multipass on Linux and macOS

Multipass turned a cached Ubuntu image into a running VM in 59 seconds on our test box. You get a real Ubuntu kernel from one command, with no hypervisor to configure.

Original content from computingforgeeks.com - post 102957

Below, you install Multipass on Linux and macOS, then take a Multipass Ubuntu instance through launch, exec, file sharing, cloud-init, snapshots and cleanup. Every timing comes from a lab run, and so does one exec bug in the current stable release that can hang your scripts.

Tested October 2026 on Multipass 1.16.4 (Ubuntu 26.04 and 24.04).

Prerequisites

To run Multipass, you need hardware virtualization, spare RAM and a few GiB of disk.

  • Ubuntu 26.04 or 24.04. Canonical ships the same snap for other distributions that run snapd, but we tested Ubuntu only.
  • A CPU with Intel VT-x or AMD-V visible to the operating system.
  • About 1 GiB of host RAM for each running instance at default size.
  • About 1.1 GiB of disk per instance, plus up to 0.8 GiB per cached image.
  • A user with sudo rights.

Our hosts were two OpenStack VMs with nested KVM. The Ubuntu 26.04 host had 2 vCPUs and 8 GB of RAM. The Ubuntu 24.04 host had 2 vCPUs and 4 GB.

Following every step keeps up to five instances running at once, so give the host about 8 GB of RAM. On a 4 GB host, keep at most two instances running, which is what our 4 GB host ran. Stop any instance the current step does not use with multipass stop, and purge primary with multipass delete --purge primary right after its mount check in Step 5.

Step 1: Confirm KVM Is Available

On Linux, Multipass runs every instance on QEMU with KVM, so /dev/kvm must exist.

To confirm KVM, check the device node and the CPU flags:

ls -l /dev/kvm
grep -cE 'vmx|svm' /proc/cpuinfo

A device node and any count above zero mean KVM is usable:

crw-rw---- 1 root kvm 10, 232 Oct 13 23:48 /dev/kvm
4

When Multipass runs inside a VM, the hypervisor has to pass VT-x or AMD-V through. If /dev/kvm is missing there, enable nested virtualization on the host first. ARM64 CPUs have no vmx or svm flag, so on an ARM host the device node is the only check.

Step 2: Install Multipass

Canonical ships Multipass as a snap on Linux and as a signed installer on macOS.

Install on Linux

Install the snap from the stable channel:

sudo snap install multipass

The snap was installed in 55.6 seconds on the 26.04 host and 57.9 seconds on 24.04:

multipass 1.16.4 from Canonical** installed

Once the snap is in place, confirm that the client and the daemon report the same version:

multipass version

Both halves answered on both hosts:

multipass   1.16.4
multipassd  1.16.4

Later upgrades are handled by snapd automatically.

On Debian, Fedora or Rocky Linux, set up snapd first with our guides for snapd on Debian, Fedora and Rocky Linux. The same snap install command follows. Canonical notes that your user must belong to the group that owns the Multipass socket, which can be wheel or admin rather than sudo there.

Error: “failed to open file ‘/var/snap/multipass/common/data/multipassd/multipass_root_cert.pem'”

Our first multipass version, run the moment the snap finished, failed like this:

[error] [client] Caught an unhandled exception: failed to open file '/var/snap/multipass/common/data/multipassd/multipass_root_cert.pem': No such file or directory(2)

Multipass had not written the daemon certificate yet. If you see this, wait a few seconds and rerun the command.

In a provisioning script, poll for the daemon line. multipass version exits 0 even when the daemon is down and prints only the client line, so the exit code alone proves nothing:

until multipass version 2>/dev/null | grep -q '^multipassd'; do sleep 1; done

With the daemon stopped, this loop kept waiting. It returned 3 seconds after the daemon came back.

Install on macOS

On a Mac, download the .pkg from the Multipass install page and run it. If you use Homebrew, install the same package as a cask:

brew install --cask multipass

Canonical lists macOS 14 Sonoma or newer and an admin account as requirements. The Mac installer was not tested for this guide. You use the same CLI on both platforms, and every number below comes from the Linux hosts.

Step 3: Launch a Multipass Ubuntu VM

One command downloads the current LTS image and boots it. First, see what you can launch:

multipass find

The catalogue on our 26.04 host:

Image                       Aliases           Version          Description
core                        core16            20200818         Ubuntu Core 16
core18                                        20211124         Ubuntu Core 18
core20                                        20230119         Ubuntu Core 20
core22                                        20230717         Ubuntu Core 22
core24                                        20240603         Ubuntu Core 24
core26                                        20260506         Ubuntu Core 26
22.04                       jammy             20261004         Ubuntu 22.04 LTS
24.04                       noble             20260926         Ubuntu 24.04 LTS
26.04                       resolute,lts      20260927         Ubuntu 26.04 LTS
daily:26.10                 stonking,devel    20261006         Ubuntu 26.10
appliance:adguard-home                        20200812         Ubuntu AdGuard Home Appliance
appliance:mosquitto                           20200812         Ubuntu Mosquitto Appliance
appliance:nextcloud                           20200812         Ubuntu Nextcloud Appliance
appliance:openhab                             20200812         Ubuntu openHAB Home Appliance
appliance:plexmediaserver                     20200812         Ubuntu Plex Media Server Appliance

Blueprint (deprecated)      Aliases           Version          Description
anbox-cloud-appliance                         latest           Anbox Cloud Appliance
charm-dev                                     latest           A development and testing environment for charmers
docker                                        0.4              A Docker environment with Portainer and related tools
jellyfin                                      latest           Jellyfin is a Free Software Media System that puts you in control of managing and streaming your media.
minikube                                      latest           minikube is local Kubernetes
ros2-humble                                   0.1              A development and testing environment for ROS 2 Humble.
ros2-jazzy                                    0.1              A development and testing environment for ROS 2 Jazzy.

26.04 carries the lts alias, so it is picked when you launch without an image name. Blueprints are marked deprecated, so you should build on plain images and cloud-init instead.

Launch an instance named web01:

multipass launch --name web01

Our first launch took 73.2 seconds, image download included.

List your instances:

multipass list

web01 is running with a private address:

Name                    State             IPv4             Image
web01                   Running           10.248.91.158    Ubuntu 26.04 LTS

To see the resources it got, ask for its details:

multipass info web01

Defaults are 1 CPU, 1 GiB of RAM and a 5 GiB disk:

Name:           web01
State:          Running
Snapshots:      0
IPv4:           10.248.91.158
Release:        Ubuntu 26.04.1 LTS
Image hash:     8800651811af (Ubuntu 26.04 LTS)
CPU(s):         1
Load:           1.33 0.40 0.14
Disk usage:     2.2GiB out of 4.8GiB
Memory usage:   352.7MiB out of 950.7MiB
Mounts:         --

The version check, launch, list and info as one terminal session on the 26.04 host:

Multipass launch, list and info output for a default Ubuntu instance on Ubuntu 26.04

On Linux, every instance sits on mpqemubr0, a NAT bridge served by its own dnsmasq. Its subnet was 10.248.91.0/24 on the 26.04 box and 10.122.3.0/24 on the 24.04 box, so expect a different one on yours. You can reach instances from the host, which the curl test in Step 7 relies on.

multipass networks lists the host interfaces you can bridge with --network or --bridged. On Linux, Multipass needs NetworkManager to create that bridge, and Ubuntu Server ships without it, so there you build the bridge with Netplan first. We did not bridge on these cloud hosts.

Launch a second instance now. Later steps use db01 for the native mount and the suspend test:

multipass launch --name db01

Once the image was cached, db01 took 58.7 seconds, so most of the wait is boot and cloud-init rather than the download.

Step 4: Choose Release and Size

To pick a release and size, pass both at launch time. Here, app01 gets Ubuntu 24.04 with 2 CPUs, 2 GiB of RAM and a 15 GiB disk:

multipass launch 24.04 --name app01 --cpus 2 --memory 2G --disk 15G

Launching app01 took 63.2 seconds, including the 24.04 image download. Confirm the sizing:

multipass info app01

All three values reached the guest:

Name:           app01
State:          Running
Snapshots:      0
IPv4:           10.248.91.165
Release:        Ubuntu 24.04.5 LTS
Image hash:     6a81c37564db (Ubuntu 24.04 LTS)
CPU(s):         2
Load:           1.70 0.48 0.16
Disk usage:     1.9GiB out of 14.4GiB
Memory usage:   384.8MiB out of 1.9GiB
Mounts:         --

If you plan real workloads, give them more than the default disk. A fresh default instance already used 2.2 GiB of its 4.8 GiB.

Step 5: Run Commands

exec runs one command and returns. shell gives you an interactive login.

Run a single command inside web01:

multipass exec web01 -- lsb_release -ds

You get the release string back:

Ubuntu 26.04.1 LTS

Commands run as the ubuntu user in its home directory:

multipass exec web01 -- bash -c "whoami; pwd; nproc"

User, directory and CPU count:

ubuntu
/home/ubuntu
1

To work interactively, open a login shell:

multipass shell web01

You land on the standard Ubuntu login banner and prompt. Type exit to return to the host:

Welcome to Ubuntu 26.04.1 LTS (GNU/Linux 7.0.0-34-generic x86_64)
 * Documentation:  https://docs.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/pro
 System information as of Wed Oct 14 00:11:49 UTC 2026
  System load:  0.19              Processes:             119
  Usage of /:   65.6% of 3.70GB   Users logged in:       0
  Memory usage: 25%               IPv4 address for ens3: 10.248.91.158
  Swap usage:   0%
Expanded Security Maintenance for Applications is not enabled.
35 updates can be applied immediately.
30 of these updates are standard security updates.
To see these additional updates run: apt list --upgradable
Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status
ubuntu@web01:~$

If you run multipass shell with no name, Multipass launches one more 1 GiB instance called primary and mounts your home directory into it:

multipass shell

Exit that shell, then check the mount from the host:

multipass info primary | grep -A1 Mounts

Our home directory appeared as ~/Home inside the guest:

Mounts:         /home/klinsmann => Home
                    UID map: 1000:default

exec loops on exit status 4

On 1.16.4, a remote exit status of 4 makes the client run the command again, with no end. To count the runs in 15 seconds, use this one-liner:

timeout 15 multipass exec web01 -- sh -c "echo run; exit 4" | grep -c run

We got 93 runs on the 26.04 host and 89 to 91 on the 24.04 host:

93

Exit statuses 1, 3 and 5 ran once each. Because systemctl is-active returns 4 for a unit that does not exist, a health check against a missing service hangs forever. We hit it after purging nginx, when a status check never came back.

Multipass reserves return code 4 for a Retry signal inside the client, and the remote status collides with it. Upstream tracked this as issue #3771, and PR #4567 fixed it in the 1.17 line. Neither 1.16.4 nor the 1.16.5 release candidate includes the fix. On the 1.17 release candidate from the beta channel, the same test ran once and the client returned 4.

Until you run 1.17, keep the remote status away from 4. This health check remaps 4 to 104 and passes every other code through:

multipass exec web01 -- sh -c 'systemctl is-active nginx; rc=$?; [ "$rc" -eq 4 ] && rc=104; exit "$rc"'

The state prints once and the client exits 104, so a failing check still fails:

inactive

When you only want the text and not the status, append || true instead. The client then exits 0:

multipass exec web01 -- sh -c "systemctl is-active nginx || true"

Same output, exit 0:

inactive

On the 24.04 host, the loop and the workaround side by side:

multipass exec repeating a command that exits with status 4, and the || true workaround

Error: “unsupported machine type” after leaving the beta

This only applies if you moved to the beta channel with sudo snap refresh multipass --beta and then went back to 1.16.4 with sudo snap revert multipass. When snapd stops the daemon for the switch, Multipass suspends running instances. The 1.17 QEMU saves that state with machine type pc-i440fx-10.0, which the 1.16.4 QEMU cannot load.

multipass list still showed both of our instances as Running, but every exec failed:

exec failed: ssh connection failed: 'No route to host'

The real cause only appears in the daemon journal:

sudo journalctl -u snap.multipass.multipassd -o cat | grep "unsupported machine type"

Each daemon start logs one line per instance. Ours shows four because neither multipass restart nor sudo snap restart multipass cleared it:

qemu-system-x86_64: unsupported machine type
qemu-system-x86_64: unsupported machine type
qemu-system-x86_64: unsupported machine type
qemu-system-x86_64: unsupported machine type

A forced stop deletes the suspend image, so the next start is a cold boot. Canonical warns that --force can corrupt a running instance, so use it only on instances in this state, and repeat it for each one:

multipass stop --force web01
multipass start web01

snap revert keeps tracking the beta channel, so a later refresh would pull the beta again. Switch back to stable:

sudo snap switch --channel=latest/stable multipass

snap info multipass then reports tracking: latest/stable.

Step 6: Share Files

transfer copies files once. mount shares a host directory live.

Create a directory to share. Our test file was 256 MiB of random data:

mkdir -p ~/shared
dd if=/dev/urandom of=~/shared/blob.bin bs=1M count=256 status=none

Copy it into the instance:

multipass transfer ~/shared/blob.bin web01:/home/ubuntu/

Copying took 2.66 seconds. To check that it arrived, list it inside the guest:

multipass exec web01 -- ls -lh /home/ubuntu/blob.bin

All 256 MiB, owned by the ubuntu user:

-rw-rw-r-- 1 ubuntu ubuntu 256M Oct 13 23:54 /home/ubuntu/blob.bin

Classic mount over SSHFS

Classic is the default mount type. Mount the directory into web01:

multipass mount ~/shared web01:/home/ubuntu/shared

Our first mount took 18.8 seconds, because the multipass-sshfs snap was installed inside the guest during that time. Verify the filesystem type:

multipass exec web01 -- findmnt -no SOURCE,FSTYPE /home/ubuntu/shared

Classic mounts are SSHFS under FUSE:

:/home/klinsmann/shared fuse.sshfs

Native mount over 9p

Native mounts use file sharing built into the hypervisor. They can only be attached to a stopped instance. Against a running one, Multipass refuses:

mount failed: Please stop the instance db01 before attempting native mounts.

Stop the instance, add the mount, then start it again:

multipass stop db01
multipass mount --type native ~/shared db01:/home/ubuntu/shared
multipass start db01

Inside the guest it shows up as 9p over virtio:

multipass exec db01 -- findmnt -no SOURCE,FSTYPE,OPTIONS /home/ubuntu/shared

Note the 512,000-byte msize:

m9108290a489134bea4b8606eb1a674 9p rw,relatime,access=client,msize=512000,trans=virtio

Mount speed compared

Both types were measured from 1-CPU instances on the 26.04 host. Each run wrote 256 MiB with dd and conv=fsync, then read the 256 MiB test file back after dropping caches on host and guest.

Mount typeWrite, 3 runsRead, 3 runsCreate 2,000 x 4 KiB filesList and delete
Classic (SSHFS)85, 83, 81 MB/s99, 101, 100 MB/s12.6 s3.2 s
Native (9p)24, 26, 24 MB/s29, 30, 29 MB/s12.1 s6.4 s
Guest local disknot measurednot measured7.1 snot measured

On these nested KVM hosts, classic was about 3.4 times faster than native for large files. Native only matched it on small-file creates, and deletes took twice as long. Measure both on your own hardware before you switch types.

To remove a single mount, name its target:

multipass umount web01:/home/ubuntu/shared

multipass umount db01 removes every mount on db01 in one go.

Step 7: Provision with cloud-init

A cloud-init file turns a launch into a configured server. Create one in your home directory:

vim ~/web-init.yaml

Add packages, a web page and a command to run on first boot:

#cloud-config
package_update: true
packages:
  - nginx
  - htop
write_files:
  - path: /var/www/html/index.html
    content: |
      <h1>web02 provisioned by cloud-init</h1>
runcmd:
  - systemctl enable --now nginx

Launch an instance with it:

multipass launch --name web02 --cloud-init ~/web-init.yaml

With nginx in the package list, the launch took 64.8 seconds. Confirm cloud-init finished:

multipass exec web02 -- cloud-init status

A clean run reports done:

status: done

To fetch the page from the host, pull the IPv4 address from the third CSV field of multipass info:

curl -s http://$(multipass info web02 --format csv | tail -1 | cut -d, -f3)/

nginx serves the file cloud-init wrote:

<h1>web02 provisioned by cloud-init</h1>

You can reuse the same user-data for VMs created with virt-install on plain KVM.

Step 8: Suspend, Resize and Snapshot

Suspend is the fast path. A resume took 2.3 seconds, while a cold start took 26.8 seconds.

Suspend db01, then bring it back. If you stopped db01 earlier on a 4 GB host, start it first, because suspend does nothing to a stopped instance:

multipass suspend db01
multipass start db01

Each step took 2.3 seconds. While suspended, multipass list shows no address:

db01                    Suspended         --               Ubuntu 26.04 LTS

Snapshot before you change it

We ran the snapshot, resize and restore sequence on the 24.04 host, in this order. The outputs come from that run, apart from the snapshot error and timing from the 26.04 host.

Snapshots need a stopped instance. On a running one you get this:

snapshot failed: Multipass can only take snapshots of stopped instances.

Stop web02 and take a named snapshot:

multipass stop web02
multipass snapshot web02 --name before-upgrade --comment "clean nginx box"

The snapshot was written in 0.33 seconds:

Snapshot taken: web02.before-upgrade

List snapshots across all instances:

multipass list --snapshots

One snapshot, with its comment:

Instance   Snapshot         Parent   Comment
web02      before-upgrade   --       clean nginx box

Resize the stopped instance

While web02 is still stopped, change CPUs, memory and disk with multipass set:

multipass set local.web02.cpus=2
multipass set local.web02.memory=2G
multipass set local.web02.disk=10G

Read each value back. On 1.16.4, multipass get takes one key per call, and three keys in one call fail with Need at most one setting key.

multipass get local.web02.cpus
multipass get local.web02.memory
multipass get local.web02.disk

All three changed:

2
2.0GiB
10.0GiB

Disks only grow. An attempt to go from 10 GiB to 8 GiB failed:

set failed: Invalid setting 'local.web02.disk=8G': Disk can only be expanded

Start web02 and check the new size:

multipass start web02
multipass info web02 | grep -E "Snapshots|CPU|Disk usage|Memory"

The guest now has 2 CPUs, 2 GiB and a 10 GiB disk:

Snapshots:      1
CPU(s):         2
Disk usage:     2.2GiB out of 9.6GiB
Memory usage:   394.0MiB out of 1.9GiB

Restore the snapshot

To test a restore, purge nginx from web02:

multipass exec web02 -- sudo apt-get -qq -y purge nginx nginx-common

Then run the health check from Step 5 against web02, in its exit-4-safe form:

multipass exec web02 -- sh -c 'systemctl is-active nginx; rc=$?; [ "$rc" -eq 4 ] && rc=104; exit "$rc"'

nginx is gone, and the client exits 104:

inactive

Stop web02 and roll it back:

multipass stop web02
multipass restore web02.before-upgrade --destructive

--destructive discards the current state of the instance. The restore confirms:

Snapshot restored: web02.before-upgrade

Start web02 and rerun the same health check:

multipass start web02
multipass exec web02 -- sh -c 'systemctl is-active nginx; rc=$?; [ "$rc" -eq 4 ] && rc=104; exit "$rc"'

nginx is back, and the check exits 0:

active

The sizing went back too. Check it the same way as after the resize:

multipass info web02 | grep -E "Snapshots|CPU|Disk usage|Memory"

1 CPU, 1 GiB and a 5 GiB disk, the values from snapshot time:

Snapshots:      1
CPU(s):         1
Disk usage:     2.2GiB out of 4.8GiB
Memory usage:   377.5MiB out of 950.7MiB

If you resize an instance, take a fresh snapshot afterwards, or a restore quietly undoes the change.

Step 9: Delete, Recover and Purge

delete is reversible until you purge. Delete app01:

multipass delete app01

multipass list keeps it, marked Deleted. Your other rows depend on which instances you kept or stopped. Ours was captured before the primary instance existed:

Name                    State             IPv4             Image
app01                   Deleted           --               Ubuntu 24.04 LTS
db01                    Running           10.248.91.209    Ubuntu 26.04 LTS
web01                   Running           10.248.91.158    Ubuntu 26.04 LTS
web02                   Running           10.248.91.191    Ubuntu 26.04 LTS

Bring it back with multipass recover app01, then start it. To remove an instance for good, purge it:

multipass delete --purge app01

Purging app01 shrank the instance directory from 5.3 GiB to 4.3 GiB. To clear the whole lab, stop and purge everything:

multipass stop --all
multipass delete --all --purge

Stopping four instances took 16.3 seconds. The purge took 0.37 seconds, and multipass list printed No instances found.

A purge leaves the image cache alone, and ours still held 1.4 GiB for the 26.04 and 24.04 images. To remove Multipass and its data completely, run:

sudo snap remove --purge multipass

snapd confirms, and /var/snap/multipass is gone:

multipass removed

On macOS, Canonical documents an uninstall script instead. It asks whether to delete your VMs and daemon data as well. If you installed with Homebrew, run the script before brew uninstall --cask multipass, because the cask uninstall deletes the script and leaves the daemon data under /var/root/Library.

sudo sh "/Library/Application Support/com.canonical.multipass/uninstall.sh"

Measured Footprint per Instance

A default instance cost about 1 GiB of host RAM and 1.1 GiB of disk on the 26.04 host.

MeasurementUbuntu 26.04 hostUbuntu 24.04 host
snap install55.6 s57.9 s
First launch, image download included73.2 s75.9 s
Launch from cached image58.7 snot measured
Launch with cloud-init and nginx64.8 snot measured
Cold start / suspend / resume26.8 s / 2.3 s / 2.3 snot measured
Host RAM (QEMU RSS), default instance after boot1,069 to 1,070 MiBnot measured
Disk per default instance1.09 GiB qcow2, 5 GiB virtualnot measured
Cached image826 MiB (26.04), 597 MiB (24.04)not measured
transfer, 256 MiB2.66 snot measured
exec status 4 loop, runs in 15 s9389 to 91

Host RAM is the number to watch. web01 reported 352.7 MiB in use inside the guest, while its QEMU process held 1,070 MiB. Four instances held 3,753 MiB together and left 3,577 MiB available on the 8 GB host.

Every instance is a full qcow2 copy of the image, with no backing file. Disk grows by 0.8 to 1.1 GiB per launch, however many instances share a release.

When you need libvirt storage pools or guests bridged onto your LAN, move up to KVM and QEMU on Ubuntu 26.04. For multi-machine labs driven from a file, Vagrant is the closer fit.

Keep reading

Upgrade Ubuntu 24.04 to Ubuntu 26.04 LTS (Step by Step) Ubuntu Upgrade Ubuntu 24.04 to Ubuntu 26.04 LTS (Step by Step) UFW Firewall Commands with Examples on Ubuntu 26.04 / 24.04 Security UFW Firewall Commands with Examples on Ubuntu 26.04 / 24.04 Claude Code Cheat Sheet: Commands, Shortcuts and Flags (PDF) AI Claude Code Cheat Sheet: Commands, Shortcuts and Flags (PDF) Upgrade a Single Package on Ubuntu / Debian with apt Debian Upgrade a Single Package on Ubuntu / Debian with apt APT Cheat Sheet: apt and apt-get Commands for Ubuntu/Debian Cheat Sheets APT Cheat Sheet: apt and apt-get Commands for Ubuntu/Debian Prometheus MySQL exporter init script for SysV init system Prometheus Prometheus MySQL exporter init script for SysV init system

Leave a Comment

Press ESC to close