Skip to content

Vagrant and Multipass: Local VM Management for Development

DodaTech Updated 2026-06-22 6 min read

In this tutorial, you'll learn Vagrant and Multipass for local VM management including provisioning, networking, shared folders, and using VMs for reproducible development environments.

Why Local VMs Matter

Containers solve many environment problems, but some situations demand a full virtual machine: testing system-level configuration, experimenting with different operating systems, setting up network environments, or running software that does not work in containers. Vagrant and Multipass make VM management as easy as running a container -- one command creates, provisions, and destroys a complete virtual machine.

By the end of this guide, you will provision VMs with Vagrant and Multipass, share folders, configure networking, and automate setup with provisioning scripts.

What are Vagrant and Multipass?

Vagrant is a tool for building and managing virtual machine environments. It uses a Vagrantfile to define the VM configuration in code. Multipass is a simpler tool from Canonical that launches Ubuntu VMs with minimal configuration.

flowchart TD
  A[Vagrantfile] --> B[Vagrant]
  B --> C[Provider]
  C --> D[VirtualBox]
  C --> E[VMware]
  C --> F[Hyper-V]
  B --> G[Provisioning]
  G --> H[Shell Scripts]
  G --> I[Ansible]
  G --> J[Puppet]
  K[Multipass] --> L[Launch VM]
  L --> M[Ubuntu Instance]
  M --> N[Cloud-init]

Multipass: Quick Ubuntu VMs

Multipass is the simplest way to get an Ubuntu VM.

Installation

# macOS
brew install multipass

# Linux (snap)
sudo snap install multipass

# Verify
multipass version

Basic Usage

# Launch a VM
multipass launch --name dev-vm --cpus 2 --memory 2G --disk 10G

# List VMs
multipass list

# Shell into VM
multipass shell dev-vm

# Execute a command inside VM
multipass exec dev-vm -- ls -la

# Mount a directory
multipass mount /path/to/project dev-vm:/home/ubuntu/project

# Stop VM
multipass stop dev-vm

# Start VM
multipass start dev-vm

# Delete VM
multipass delete dev-vm
multipass purge

Expected Output

$ multipass launch --name dev-vm --cpus 2 --memory 2G --disk 10G
Launched: dev-vm

$ multipass list
Name                    State             IP             Image
dev-vm                  Running           192.168.64.2   Ubuntu 24.04 LTS

Cloud-Init with Multipass

# cloud-init.yaml
#cloud-config
packages:
  - build-essential
  - git
  - python3-pip
  - docker.io

runcmd:
  - systemctl enable docker
  - systemctl start docker
  - usermod -aG docker ubuntu
multipass launch --name dev-vm --cloud-init cloud-init.yaml

Installation

# macOS
brew install vagrant

# Linux
sudo apt install vagrant -y

# Also install a provider (VirtualBox recommended)
brew install --cask virtualbox

Vagrantfile

# Vagrantfile
Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/jammy64"
  config.vm.hostname = "dev-machine"

  # Network
  config.vm.network "private_network", ip: "192.168.56.10"
  config.vm.network "forwarded_port", guest: 80, host: 8080

  # Shared folder
  config.vm.synced_folder "./project", "/home/vagrant/project"

  # Provider configuration
  config.vm.provider "virtualbox" do |vb|
    vb.memory = "2048"
    vb.cpus = 2
    vb.name = "dev-machine"
  end
end

Basic Commands

# Start VM
vagrant up

# SSH into VM
vagrant ssh

# Stop VM
vagrant halt

# Suspend VM
vagrant suspend

# Destroy VM
vagrant destroy

# Reload (re-apply config)
vagrant reload

# Check status
vagrant status

Expected Output

$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'ubuntu/jammy64'...
==> default: Matching MAC address for NAT networking...
==> default: Setting the name of the VM: dev-machine
==> default: Fixed port collision for 22 => 2222. Now on port 2200.
==> default: Machine booted and ready!
==> default: Mounting shared folders...
    default: /vagrant => /Users/alice/projects/myapp

Provisioning

Shell Provisioning

Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/jammy64"

  # Inline script
  config.vm.provision "shell", inline: <<-SHELL
    apt-get update
    apt-get install -y nginx git docker.io
    systemctl enable nginx
    systemctl start nginx
  SHELL

  # External script
  config.vm.provision "shell", path: "bootstrap.sh"
end

Ansible Provisioning

Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/jammy64"

  config.vm.provision "ansible" do |ansible|
    ansible.playbook = "playbook.yml"
    ansible.inventory_path = "inventory"
    ansible.verbose = true
  end
end

Multiple Provisioners

Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/jammy64"

  config.vm.provision "shell", path: "install-deps.sh"
  config.vm.provision "shell", path: "configure-app.sh"
  config.vm.provision "shell", path: "start-services.sh"
end

Multi-Machine Setup

Vagrant.configure("2") do |config|
  config.vm.provider "virtualbox" do |vb|
    vb.memory = "1024"
    vb.cpus = 1
  end

  config.vm.define "web" do |web|
    web.vm.box = "ubuntu/jammy64"
    web.vm.hostname = "web-server"
    web.vm.network "private_network", ip: "192.168.56.10"
    web.vm.provision "shell", inline: "apt-get install -y nginx"
  end

  config.vm.define "db" do |db|
    db.vm.box = "ubuntu/jammy64"
    db.vm.hostname = "db-server"
    db.vm.network "private_network", ip: "192.168.56.11"
    db.vm.provision "shell", inline: "apt-get install -y postgresql"
  end

  config.vm.define "api" do |api|
    api.vm.box = "ubuntu/jammy64"
    api.vm.hostname = "api-server"
    api.vm.network "private_network", ip: "192.168.56.12"
  end
end
# Start specific machine
vagrant up web

# Start all machines
vagrant up

# SSH to a specific machine
vagrant ssh web

Box Management

# List installed boxes
vagrant box list

# Add a box
vagrant box add ubuntu/jammy64

# Update boxes
vagrant box update

# Remove old box versions
vagrant box prune

Available Boxes

Box Name OS Size
ubuntu/jammy64 Ubuntu 22.04 LTS ~600 MB
ubuntu/noble64 Ubuntu 24.04 LTS ~650 MB
debian/bookworm64 Debian 12 ~500 MB
centos/7 CentOS 7 ~500 MB
bento/rockylinux-9 Rocky Linux 9 ~600 MB

Comparison Table

Feature Vagrant Multipass
Base OS Any (via boxes) Ubuntu only
Configuration file Vagrantfile CLI + cloud-init
Provisioning Shell, Ansible, Puppet, Chef cloud-init
Networking Public, private, forwarded ports NAT (automatic)
Provider VirtualBox, VMware, Hyper-V, Docker HyperKit, QEMU
Learning curve Moderate Low
Snapshot support Yes No
Multi-machine Yes No
Use case Complex environments Quick Ubuntu VMs

Common Errors

Problem Cause Fix
VT-x is not available Virtualization disabled in BIOS Enable VT-x/AMD-V in BIOS/UEFI settings
vagrant up hangs on SSH SSH timeout, wrong key Run vagrant ssh-config to debug, then vagrant reload
VM cannot access internet NAT misconfigured Use config.vm.provider with correct NAT settings
Shared folder not mounting Guest Additions mismatch Run vagrant plugin install vagrant-vbguest
Multipass launch fails Insufficient disk space Free up space or increase disk allocation

Practice Questions

1. What is a Vagrant box?

A Vagrant box is a base image (template) used to create a VM. It contains a pre-installed operating system.

2. How do you share a folder between host and VM in Vagrant?

Use config.vm.synced_folder "host_path", "guest_path" in the Vagrantfile.

3. What is Multipass cloud-init?

A configuration file passed to Multipass at launch that specifies packages to install and commands to run.

4. How do you forward a port in Vagrant?

config.vm.network "forwarded_port", guest: 80, host: 8080.

5. What is the difference between vagrant halt and vagrant suspend?

halt shuts down the VM completely. suspend saves the VM state to disk and resumes quickly.

Challenge

Create a multi-machine Vagrant setup that simulates a production environment: a web server running Nginx, an application server with Node.js, and a database server with PostgreSQL. Use private networking for inter-machine communication and shell provisioning to install and configure each service.

Real-World Task

Use Vagrant to create a disposable test environment for a project. The VM should have Docker installed, mount the project directory, forward the necessary ports, and run the application's test suite on vagrant up through provisioning. Verify that vagrant destroy cleans up completely.

Should I use Vagrant or Multipass?

Use Multipass for quick Ubuntu VMs with minimal setup. Use Vagrant for complex environments, multi-machine setups, or when you need a VM configuration in version control.

Can Vagrant use Docker as a provider?

Yes. Vagrant can use Docker as a lightweight provider, though Docker containers are not full VMs and lack kernel-level isolation.

Are VMs slower than containers?

Yes. VMs have more overhead because they run a full operating system including a kernel. However, VMs provide stronger isolation and can run different OS kernels.

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro