Vagrant and Multipass: Local VM Management for Development
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
Vagrant: Full-Featured VM Management
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.
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro