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.
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 move large files to another disk you should consider this before you install. If you have a larger D drive, then you might want to set the environment variable MULTIPASS_STORAGE to point to a location 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 on all systems without regard to performance. They use a terribly inefficient tool that shares directories over an SSH connection.
This is fine for casual access to files, but not for anything that does a lot of I/O. There are other options (NFS, CIFS - a.k.a. Windows Shares, …). I will update this if anyone proposes a best practice.
This is one of the places where a multi-user machine would have problems with security. Mounts are shipped disabled, and if you are running on a single user environment or you trust all your users, 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. Starting with Multipass 10 you can also change initial parameters by stopping the VM and issuing a multipass set command with the name of the vm and “cpus”, “memory”, or “disk”. For example, to expands the default 5G disk to something larger type:
multipass set local.vmname.disk=100G
Hyper-V virtual disk file are dynamic and expand only when it is necessary because new data is being added to them, so overestimating the disk size in a multipass command does not use disk space. Running a bad program that fills up the disk is when you have a problem.
It is still useful to get the number of adapters correct in the multipass launch by adding as many --network parameters as you need. The IP addresses of the adapters are specified in the file /etc/netplan/50-cloud-init.yaml. Each adapter is identified by its Ethernet address which is dynamically assigned by Hyper-V unless you explicitly add it to the --network parameter on the multipass launch. It is easier if you get a file that is already configured for the adapters and then only have to change the IP parameters rather than change the whole thing if you add an adapter later on.
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.
If you have been reading carefully, you may have notices that the amount of memory on launch is set by --mem, but if you change it after launch you use “memory” as in multipass set local.vmname.memory. Of course, it is easier to change memory with the Hyper-V Manager if you are comfortable using it.
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
When it is installed, Multipass generates SSH keys and stores the secret key in C:\ProgramData\multipass\data\ssh-keys.
On each VM, Multipass creates a user named “ubuntu” with sudo privileges and the matching public SSH key. It then has its own internal version of ssh and scp programs that it uses to connect to the VMs over the Hyper-V Default network. All the multipass commands that communicate to the VM (exec, shell, mount, transfer, etc.) use this internal SSH.
However, ubuntu does not have a password unless you assign one. You should always do this in case the ssh connection to the VM is broken, so you can login to the VM using the Hyper-V console window and the password you created.
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 privileges, and store your normal SSH public key in your home directory.
This is useful if Multipass is clobbered on your machine and you have to fall back on standard VM communication. It is also useful if you move the VM to a different machine where the Multipass on that machine does not recognize VMs it did not itself create.
Until Version 1.9 Multipass stored its files in a directory that Microsoft believed it could delete on any annual major version upgrade of Windows 10 or 11. Even if that is fixed, you are given an opportunity to delete everything in the middle of the Setup dialogs each time Multipass updates its software with new fixes. Hit the Yes button instead of the No button and it is all gone.
So you should always create Multipass VMs that can stand on their own without a multipass command. You should also take advantage of Hyper-V tools to checkpoint and backup and export VMs. You should also find and backup the multipass ssh keys.
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.
On each VM, do a “sudo passwd ubuntu” and give the built in ubuntu user a real password and not just SSH keys.
Add a second user with your own normal SSH login key and a password, and give it SUDO privileges.
Find the Multipass ssh key and save the file separately (it has no passcode).
Don’t count on “multipass mount”. Find another way to share files. For example, do a “sudo apt install cifs-utils” and learn how to connect to a Windows Shared disk directory. This is a good article.
Backup VMs using Hyper-V “Export”. Not only does this allow you to restore after various problems, but is also a convenient way to move VMs from one host to another. 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, which is a second excellent reason for creating VMs that can stand on their own without the multipass command.
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 https://cloudinit.readthedocs.io/en/latest/topics/network-config-format-v2.html . 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 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.
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 https://cloudinit.readthedocs.io/en/latest/topics/network-config-format-v2.html .