Multipass (Personal Linux VM SpinUp)
Multipass is a Windows command line tool from Canonical that quickly creates, manages, and discards new Ubuntu “Server” (command line only, no GUI) Hyper-V VMs. You can use it to test Linux software or to quickly build utility VMs. If you don’t like what you are testing, simply delete the VM and try something else.
This article has been updated to Multipass Version 1.10.
Unlike containers or WSL, a Linux Server VM runs “systemd” and supports components that require a background service (also known as a daemon). This allows you to run database systems and Docker itself on a Multipass VM.
Multipass VMs are configured to run well enough under Hyper-V but to minimize code complexity they tend to use features available in every system they support (including VirtualBox, Linux, and Mac), so it is not optimized for Hyper-V. You can always add missing packages.
Multipass tries to support multi-user machines, but that objective conflicts with making some things easy to use. It works best on a personal machine with only one user who is admin, because then you can do everything .
Install
A new install of Multipass stores the disk images and virtual machines in the C:\ProgramData\Multipass directory. Hyper-V can only use locations that are on a local disk (not a network share), but if you want to store these large files on another local disk, then before you install set the environment variable MULTIPASS_STORAGE to point to a directory on that disk.
You can install Multipass with the winget package manager:
winget install multipass
If you want to install it yourself, Multipass development is hosted on GitHub where you can download the latest release.
Enable Mounts (a convenience factor)
Multipass has simple commands and options to share Windows directories with Multipass VMs. This is done through the multipass mount command after the VM is created, or the --mount parameter when creating a VM. This is, however, one of the places where the authors opted first for something they could get to work the same way on all systems without regard to performance. They use a file system based on SSH that provides very poor performance.
If you need to do more than casual file transfer, you need something better. There are other options (NFS, CIFS - a.k.a. Windows Shares, …). I will update this if anyone proposes a best practice or posts some benchmarks.
Hyper-V bypasses Windows access control, and Multipass runs as a background service under a SYSTEM userid. There is no way to recreate file system access control. The multipass mount service is shipped disabled, and you have to turn it on as an administrator. After that, you acknowledge that directories are being exposed to everyone, which is why this is best done on a single user machine. To turn mounts on, open a Run as Administrator command prompt window and issue the one time command:
multipass set local.privileged-mounts=true
Choose a Base Image
To simplify installation, Multipass does not come with any Ubuntu VM images. They are available from over the network and are periodically refreshed with newer images with the latest fixes preinstalled.
The “multipass find” command will list the images available currently from the network.
C:\Users\gilbert>multipass find
Image Aliases Version Description
core core16 20200818 Ubuntu Core 16
core18 20211124 Ubuntu Core 18
snapcraft:core18 18.04 20201111 Snapcraft builder for Core 18
snapcraft:core20 20.04 20210921 Snapcraft builder for Core 20
snapcraft:core22 22.04 20220426 Snapcraft builder for Core 22
18.04 bionic 20220615 Ubuntu 18.04 LTS
20.04 focal,lts 20220615 Ubuntu 20.04 LTS
21.10 impish 20220616 Ubuntu 21.10
22.04 jammy 20220616 Ubuntu 22.04 LTS
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
anbox-cloud-appliance latest Anbox Cloud Appliance
charm-dev latest A development and testing environment for charmers
docker latest A Docker environment with Portainer and related tools
minikube latest minikube is local Kubernetes
The “multipass launch” command creates a new VM. The single positional parameter (at the end of the command) is the name or alias of one of the images listed above (the default is “lts”, but you will note that several months after 22.04 was released they have not changed “lts” to point to it).
The last four image names (including docker and minikube) are Blueprints. A Blueprint is a YAML file that has instructions to download an image and then add additional packages and run programs to specially configure the VM. There is a GitHub project that contains the source of these Blueprints.
Generally the best choice is the most recent release. In this case it is “22.04” which because it is also an LTS is likely to be a good choice for a long while.
Create the VM
You create a new VM with the “multipass launch …” command. You can specify the number of CPUs, amount of memory, size of the disk, and the number of network adapters and which network they connect to.
A Multipass VM is also a Hyper-V VM. The Hyper-V Manager allows you to change the number of CPUs and the amount of memory. You can also attach or detach a virtual network adapter to a Hyper-V virtual network (virtual switch). Starting with Multipass 10 you can also change the number of CPUs or amount of memory using a Multipasss command, but the Hyper-V Manager interface is better for these type of changes.
There are still a few changes that are complicated and require some thought. Changing the size of the hard disk requires first enlarging the virtual size of the disk, then expanding the partition, and finally telling the file system to use the extra space. You can find articles that give you the Linux commands, but Multipass makes it much simpler with a command that allows you to expand (but not reduce) the disk size of a VM:
multipass set local.vmname.disk=100G
Note that Hyper-V virtual disk file are dynamic, start out small, and only increase in size when you are adding data to the disk. Therefore, it is generally a good practice to overestimate the size of the disk you will need since you are only assigning a maximum size the disk will grow to. The same amount of data will take the same amount of disk space whether the disk (maximum) size is 50G, 100G, or 200G.
In the same way, it is better to create a VM with the maximum number of network adapters you will ever need. Extra adapters that you are not using immediately can be attached to an otherwise unused private Hyper-V switch, but it is probably better if they are not attached to any switch at all (leaving them like a physical network adapter that has no cable plugged into it). The problem is that Ubuntu networks are configured in a file /etc/netplan/50-cloud-init.yaml. Each adapter is identified by its Ethernet address which is dynamically assigned by Hyper-V. If you create all the adapters you may ever use, you get a file that configures each of them then only have to change the IP address parameters on an already configured adapter.
An example of the command to create a VM is:
multipass launch -n vmname --cpus 2 --disk 127G --mem 1024M --network Sandbox 22.04
The last and only positional parameter is the image name “22.04” taken from the list of image names shown above. Multipass will download the initial image file if it is not already on your machine.
Cloud-Init
Lots of people have developed files and utilities to do configure a VM automatically when it is created by adding packages, users, groups, Certificates, keys, and other stuff. Canonical likes a tool called Cloud-Init. The “multipass launch --cloud-init “ parameter can take a file name or “-” for standard input. The file format is a bit complicated, and while some examples will be provided below, if you want the full syntax read the manual.
Of course, you can accomplish the same thing by writing a bash script, doing a “multipass transfer” of the script to the VM, and then run the script with “multipass exec” after the launch. It is up to you.
A useful trick in Powershell scripting is to put the text of the cloud-init file in the script as a multiline text literal that gets piped to the “multipass launch” and is then picked up by a “--cloud-init -” parameter where putting a dash “-” instead of a file name means “read from standard input” which is to say from the pipe. An alternative is to build a separate script that constructs the cloud-init file from parameters passed to the script, and then use that script to generate the text piped to the “multipass launch” command. Here is an example with inline text:
param (
[string] $vmname
)
# Start a Multiline text literal YAML that ends in a line beginning with "@
@"
#cloud-config
# Create my normal userid with its normal ssh key and sudo privileges
# The docker group will only exist if docker is in the package install list
users:
- name: gilbert
gecos: Howard Gilbert
shell: /bin/bash
groups: docker
ssh_authorized_keys:
- "ssh-rsa AA...094347"
sudo: ALL=(ALL) NOPASSWD:ALL
# Packages to install with sudo apt install ...
packages:
- avahi-daemon
- cifs-utils
- cockpit
# Do apt update and upgrade with latest changes
package_update: true
package_upgrade: true
# Add a snap. I like Powershell
snap:
commands:
- snap install powershell --classic
# Reboot after everything to activate all the changes
power_state:
mode: reboot
# End of text literal which gets piped to the multipass command as stdin
"@ |
multipass launch -n $vmname -d 127G -timeout 600 --cloud-init - --network Sandbox 22.04
You can add parameters to the script, and the parameters can both change the content of the cloud-init commands and the multipass launch command.
A word about packages you may want to automatically install:
avahi-daemon adds support for the mDNS protocol, where this VM can be reference from other VMs as hostname.local (where in this example hostname is the $vmname parameter of the script).
cifs-utils allows the VM to connect to the Windows host computer and access shared disk files.
cockpit is a Web based management tool for Linux. Open a browser to https://hostname.local:9090/
linux-image-virtual linux-tools-virtual linux-cloud-tools-virtual are optional packages for running Linux in a VM, including Hyper-V. The main benefit is that Hyper-V Manager can display Network addresses for all virtual adapters in the VM. The downside is that the install of the last package hangs for 2 minutes until it times out, and then because of the failure does not start the services until the next reboot (which the “power-state” at the end of the cloud-init takes care of).
If you specify a new Ubuntu image name (22.04 here) a new image file will be downloaded from the Internet and saved in the cache first and then the rest of the launch will run.
Run Commands as “ubuntu” user
During installation Multipass generates a local set of SSH keys and stores the secret key in C:\ProgramData\multipass\data\ssh-keys file.
On each VM, Multipass creates a user named “ubuntu” with sudo privileges and inserts in its home directory the matching public SSH key.
Multipass does not depend on SSH installed on the Windows system. It comes with its own SSH programs to connect to the VMs, create a session, pass commands, or transfer files. It does all this over the Default Hyper-V network.
The “ubuntu” user does not have a password, so if you lose Multipass or its private key gets clobbered you are locked out. You should use the “passwd” command to create your own password for this user. Multipass won’t use it, but if you lost Multipass (or if you feel like it) you can use the Hyper-V Manager to open a window with the hardware console of the VM and then login as “ubuntu” with the password you assigned.
But also back up the C:\ProgramData\multipass\data\ssh-keys file someplace safe, since even if Multipass was clobbered you can use the real ssh.exe client program built into current Windows to connect to the VM without multipass if you have the file (since it doesn’t appear to have a passcode and you can just point to it on the ssh command).
IMPORTANT: READ THIS
Sometimes Multipass screws up.
Sometimes you screw up and clobber Multipass files.
Otherwise, Microsoft’s annual upgrade (from say 21H2 to 22H2) screws up for you.
Your Multipass VMs are real Hyper-V VMs. You can run them from Hyper-V, login to them with a Hyper-V console window, and generally ignore Multipass if you want. You can also create your own userid, assign it sudo privileges, and store your normal SSH public key in your home directory. Then you can use Windows ssh command instead of Multipass.
You want three alternative backups: a password on the “ubuntu” user, a backup of the Multipass private key file, and your own authorized user with you own ssh key (and if you want, put your password on it too). Now if you lose Multipass control, you still have access to the VM. This is useful if you now use it for docker, or a database, or a Web server.
If you install a new Multipass today, it puts its files in C:\ProgramData which is safe. Several releases ago it put them in the C:\Windows subdirectories which was a mistake because Windows would remove them across a semiannual feature upgrade. Of course, every time winget upgrades Multipass from one minor version to the next it runs an uninstall which pops up a dialog offering you the chance to destroy all your files and VMs if you just click the Yes button. In other words, it is just too easy to lose everything.
So back up Multipass in C:\ProgramData, at least to some offline backup disk just in case.
Multipass does not do a good job of explaining how things are done. It uses a Windows feature called a “difference disk”. Each VM starts with a read-only copy of the base Ubuntu disk image file, but from this image it creates a read-write file where Windows writes all the changes that were made to the disk as it first boots up and is configured.
Directory of C:\ProgramData\Multipass\data\vault\instances\docker
06/19/2022 11:53 AM <DIR> .
07/14/2022 06:03 PM <DIR> ..
06/19/2022 11:53 AM 59,392 cloud-init-config.iso
06/19/2022 11:53 AM 1,686,110,208 ubuntu-22.04-server-cloudimg-amd64.vhdx
07/14/2022 08:17 PM 3,507,486,720 ubuntu-22.04-server-cloudimg-amd64_11B1CDD6-25BA-44B1-92A3-1C4DBFCA6924.avhdx
3 File(s) 5,193,656,320 bytes
The ubuntu-22.04-server-cloudimg-amd64.vhdx is the read-only image and the ubuntu-22.04-server-cloudimg-amd64_11B1…24.avhdx file is the read-write difference disk. Hyper-V will only show the difference disk name. You may confuse this with a similar arrangement for Hyper-V checkpoints. This is not a checkpoint but rather an option Windows provides for its virtual disk files.
If you upgrade to 22H2 and Multipass appears to have been deleted, remember that the old files are saved for a month or so in the C:\Windows.old directory. That does not, however, give you instructions for restoring your old multipass installation on the new system.
Durable Shared Files
If you count on “multipass mount” you are in trouble if the multipass configuration gets broken. Besides, the performance is pretty terrible.
A native Windows to Linux file sharing solution can be added using Windows standard file shares. On the VM do a “sudo apt install cifs-utils” and learn how to connect to a Windows Shared disk directory. This is a good article.
Export
Backup VMs or move them from one Windows system to another using Hyper-V “Export”. Note that if you do this, Multipass on the Importing host will not know about and cannot talk to a VM that was previously connected to Multipass on the Exporting host. That is why you have multiple ways to login, transfer files, and share directories.
The eth0 Network
When Multipass creates a new VM it creates a first Virtual Network Adapter and connects it to the Hyper-V Default Switch network. Default is a network that “just works out of the box” so you don’t need to configure or administer it, so you are not allowed to change or manage it. Every time the Host computer reboots, it does the equivalent of a “factory reset” on the Default network and everyone gets a new IP address.
Default provides a DHCP service that supplies each VM with an IP address, subnet mask, gateway address (the host IP address), and a DNS server address (the host IP address again). The host provides a limited DNS function by accepting a query from the network, doing the same name lookup that all your Windows applications do when looking for a name, and then returns that IP address to the VM.
The Windows host also does a NAT gateway function for all the VMs on Default. VMs send network requests to the host, where they are modified to look like they are coming from a host program and are then sent out in the same way that all Windows application traffic is sent. This means that the VMs in Default use the wireless or wired network and any VPN you have set up in the same way your Windows browser on the host computer finds and talks to Internet servers.
The dummy DNS creates for the Default VMs a dummy domain name with the fixed suffix of “.mshome.net”. When a VM calls DHCP for an IP address, it presents a hostname that is added to a table in the file C:\Windows\System32\drivers\etc\hosts.ics. This extends the normal “hosts” file in the same directory. Therefore, if the Host windows system or a VM on the Default network looks for a DNS name of “swarm1.mshome.net” and there is a “swarm1” VM on Default, then both will find the IP address of that VM, but for slightly different reasons. The VM will get back a DNS response from the dummy DNS server maintained by the host, which itself along with all the other programs on the Windows Host computer will find this name in the extended “hosts” file. Note that this also means that you can extend the set of DNS names that the VMs on Default will find by adding entries you the real Windows “hosts” file.
The Default network allows the VMs to talk to each other and to talk to the Host OS. They can act as clients to talk through the NAT gateway to servers on the home or Yale network or Internet, but no computer outside the Host can find them (they are behind a NAT that does not allow you to do “port mapping”). If you want to expose access to a VM on Default from some outside computer, you have to run a Reverse Proxy like nginx on the Host system to readdress and forward traffic to Default, and that only works for HTTP.
The Default network can be used for anything that does not require one of three features:
You cannot connect Default to a real Network Adapter and extend it to another machine.
You cannot use static IP addresses.
You cannot expose a database or AD in Default to external computers.
Multipass “ssh” commands like shell, exec, transfer, and mount that share data or execute commands on the VM must pass through the Default network. Multipass will not use any other network for this purpose.
The eth1 Network
Multipass makes it easy to create additional Ethernet adapters on your VMs and attach them to different Hyper-V switches.
A VM is then attached to both the Default network and at least one other Hyper-V network. The technical term for this is that the VM is “multihomed”. If the VM has an IP address and subnet on the second network, but no gateway address and no DNS server address, then it will use the second network to communicate locally to other VMs attached to that network, but all Internet traffic goes out through Default (which means the Host NAT gateway) and all names are resolved through the Host dummy DNS server (which also uses “hosts” files). This is the easiest configuration because you know exactly what is happening. You can configured multihomed computers with two networks that both have DNS and gateway addresses, but this is an advanced networking topic and may be different for each OS.
You are free to design your own networks, but I will outline three generic strategies that I will call HomeNet, Sandbox, and Sandbox-2.
HomeNet solves the problem of exposing a subset of your VMs to other devices on your home network. This is useful if you put something like Plex Media Server on a VM. The downside is that you do not want to expose these VMs to the Yale network if you create this configuration on your laptop. To make this work, you create a Hyper-V “External” network switch which is associated with a physical wired Ethernet adapter on your Host computer. It can be a dedicated secondary adapter or it can be the primary wired adapter on the mainboard. If the Host OS is already using this adapter, a separate virtual Ethernet adapter will be created and all the Host Internet and Ethernet configuration will be moved to it. The old adapter device will be strippped down to it bare Ethernet packet transmit and receive capability and will be attached to the Hyper-V switch where it will provide an external physical network connection to the VMs and the just created Host virtual adapter connected to the switch. VMs attached to this switch appear to be real computers on the real network and they will get home IP addresses from the physical gateway box that connects your home network to your ISP. It is better do only create such a network on a computer that you never bring to Yale, because if these VMs suddenly appear on the Yale network they are unregistered computers and someone in IT Security may notice them. However, if you only connect to the Yale network with wireless and you only connect your wired Ethernet port to your home network, you are safe.
Sandbox is a Yale-network-safe isolated “Internal” Hyper-V network with just your VMs and your Host computer. It has only one new feature that Default does not provide: you can assign static IP addresses to each VM. This allows you to run services on VMs that require a static address, although the only such services I can think of are DNS, a gateway/firewall, and Active Directory. However, you may have an application where you must configure an IP address instead of a DNS name, and then this solves the testing problem. Just create a Hyper-V “Internal” network switch with a name (I suggest calling it “Sandbox”). then you attach it to VMs by using --network Sandbox on your “multipass lauch” command. You have to manually configure the VMs to have a static IP address (instructions below). If you want to give these static IP addresses a DNS name, just add them to the Host computer’s “hosts” table and they will be vended through the Default network connection that the VMs use for dummy DNS resolution.
Sandbox-2 extends the Sandbox idea to a second development machine when your one laptop doesn’t have enough memory or cores to do all your testing. The model here is a developer with a laptop that moves between home and work, and a bigger desktop computer at one or both locations that the wired port of the laptop can be connected to when the developer is sitting at his desk. Start with the Sandbox internal network defined above. Create a separate Sandbox switch on each of the two computers. Make sure that the static IP addresses you assign to VMs are separate on the two machines. Now using an existing unused wired Ethernet port on the computers, or by buying an extra Ethernet adapter card or USB dongle when needed, convert the two Sandbox Internal switches on the two machines to External switches associated with the two previously unused and unconfigured Ethernet adapters. Plug each end of a single bare Ethernet Cat 5e or 6 cable into each of the two adapters on the two computers. The internal Sandbox switch on each computer is now connected to the other Sandbox switch. VMs on ether computer can talk to each other. You may want to generate a combined “hosts” file with the static IP addresses of all the VMs.
Multipass Network Configuration
Assuming you have already created some network, it will have been given a Hyper-V name. The “multipass networks” command lists all the network names that multipass can find:
C:\Users\gilbert>multipass networks
Name Type Description
Comcast switch Virtual Switch with external networking via "Realtek PCIe 2.5GbE Family Controller #2"
Default Switch switch Virtual Switch with internal networking
WSL switch Virtual Switch with internal networking
Sandbox switch Virtual Switch with internal networking
When you create a new VM with “multipass launch” you can tell it to create a second Virtual Network Adapter and attach it to one of these networks. Add the --network with the network name as in
multipass launch -c 4 -d 127G --network sandbox -n docker 22.04
Multipass will assume that the network has a DHCP server assigning IP addresses. If this is not the case, you have to edit /etc/netplan/50-cloud-init.yaml and assign a static IP address by deleting the references to “dhcp4” in the second (extra0) adapter and adding an addresses: […] element instead.
# This file is generated from information provided by the datasource. Changes
# to it will not persist across an instance reboot. To disable cloud-init's
# network configuration capabilities, write a file
# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
# network: {config: disabled}
network:
ethernets:
default:
dhcp4: true
match:
macaddress: 52:54:00:76:0f:3e
extra0:
addresses: [192.168.4.10/24]
match:
macaddress: 52:54:00:21:6c:16
optional: true
version: 2
In theory there is a manual at Networking config Version 2 - cloud-init 25.1 documentation . However, it just barely explains what to do and is maybe not more comprehensive than copying the example above.
Add DHCP or a Router to Sandbox
Obviously, if you just want DHCP in the Sandbox, install it on one of the Multipass VMs you create. By itself this is of limited use because it is easier to configure static IP on the VM than it is to update the DHCP configuration with a new Ethernet MAC address and an IP address.
You get more if you add a service that combines DHCP, DNS, a firewall, and a gateway to the Sandbox network. For this, you create an empty VM and install a system from a DVD image. Search the Web for “pfSense”, “opnSense”, or “openWRT” for widely used alternatives. These systems are not related to Multipass, so I just suggest them as network configuration options.
There is also a physical version of this, where you take the Ethernet adapters connecting a Sandbox 2 configuration and plug them into the wired ports on the back of a TPLink or Netgate wired router/gateway box. Then you only have to know how to admin these familiar boxes and you don’t need to learn pfSense, but at this time you are now limited to Gigabit Ethernet speed.
Make the Second Adapter Preferred
This is a highly specific problem that most people don’t have. It only occurs when the Sandbox network is connected by a Router as described above, which means that you have an unedited /etc/netplan/50-cloud-init.yaml file because you have DHCP on both Default (eth0) and Sandbox (eth1).
The problem is that Multipass automatically configures eth0 to have higher priority than eth1. This means that the VM will only use eth1 to communicate to other machines in the Sandbox subnet. All traffic to any other address gets sent through the Default network to the Host.
Default is great if you want something that just works without any configuration or setup. However, if you have spent a week or more learning how to use a pfSense VM, then you probably want to use that to get to the outside world.
This is the problem with a “multihomed” machine (a read or virtual computer with two network adapters both of which are configured to have different gateway and DNS server addresses). No operating system knows what to do, and the rules for resolving the ambiguity are usually hidden.
Except here, where the Multipass documentation clearly states that they configure eth0 to be preferred by setting the route-metric of all other adapters to 200 (while eth0 has the default value of 100 which is better). This is by design. So if Sandbox has an IP subnet of 192.168.4.0/24, then each system will only use eth1 to talk to a destination on that subnet. All other traffic to all other addresses goes out eth0, the Default network, and the Host NAT.
If you want to change this edit etc/netplan/50-cloud-init.yaml. The vanilla file installed by Multipass looks like this:
network:
ethernets:
default:
dhcp4: true
match:
macaddress: 52:54:00:0c:8d:5e
extra0:
dhcp4: true
dhcp4-overrides:
route-metric: 200
match:
macaddress: 52:54:00:e2:fc:f7
optional: true
Change the line on the second adapter where it says
route-metric: 200.
Change 200 to 50, or any number less than 100. Reboot or reload the network configuration this VM will use eth0 only to talk to addresses on the Default network and will send all non-local traffic to the gateway in Sandbox (pfSense or TPLink).
Again I will point to the same reference document for the file, which is no more helpful on this point than the previous change Networking config Version 2 - cloud-init 25.1 documentation .