# Install Vagrant and VirtualBox: Create Local Virtual Machines as Code

> Install VirtualBox and Vagrant, write a Vagrantfile for a multi-VM lab with private networking and provisioning, and use the daily commands to manage it.

- Source: https://www.itwonderlab.com/install-vagrant-virtualbox/
- Published: 2026-09-26
- Updated: 2026-09-26
- Author: Javier Ruiz Jiménez (https://www.javierruizjimenez.com/)
- Site: IT Wonder Lab (https://www.itwonderlab.com/)

---

## Why Vagrant and VirtualBox

[VirtualBox](https://www.itwonderlab.com/virtualbox/) runs virtual machines on your computer. [Vagrant](https://www.itwonderlab.com/vagrant/) describes those machines in a `Vagrantfile`, so a whole lab (three servers, their IPs and their software) starts with `vagrant up` and disappears with `vagrant destroy`. It is the base of the [Kubernetes cluster built with Ansible and Vagrant](https://www.itwonderlab.com/ansible-kubernetes-vagrant-tutorial/).

## Install on Ubuntu

```bash
sudo apt update
sudo apt install -y virtualbox

wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update && sudo apt install -y vagrant
vagrant --version
```

The repository is signed with [GnuPG](https://www.itwonderlab.com/gnupg/), which is why the key is imported first. On macOS use `brew install --cask virtualbox vagrant`; on Windows use the installers. Hardware virtualization (VT-x or AMD-V) must be enabled in the BIOS, and other hypervisors that use it (KVM, Hyper-V) can conflict with VirtualBox.

## First machine

```bash
mkdir lab && cd lab
vagrant init ubuntu/jammy64
vagrant up
vagrant ssh
```

`vagrant init` writes a `Vagrantfile`. The first `vagrant up` downloads the **box** (the base image of the VM) and boots it. `vagrant ssh` opens a shell inside.

## A lab with three servers

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

  config.vm.provider "virtualbox" do |vb|
    vb.memory = 1024
    vb.cpus = 1
  end

  (1..3).each do |i|
    config.vm.define "node#{i}" do |node|
      node.vm.hostname = "node#{i}"
      node.vm.network "private_network", ip: "192.168.56.1#{i}"
    end
  end

  config.vm.provision "shell", inline: <<-SHELL
    apt-get update -y
    apt-get install -y curl
  SHELL
end
```

- `private_network` creates an interface on a host-only network, so the VMs reach each other and your computer reaches them, with fixed IPs. VirtualBox only allows ranges inside `192.168.56.0/21` unless you edit `/etc/vbox/networks.conf`.
- The `shell` provisioner runs when the machine is created.

## Provision with Ansible

Replace the shell provisioner with a playbook (see [Install Ansible](https://www.itwonderlab.com/install-ansible-first-playbook/)):

```ruby
  config.vm.provision "ansible" do |ansible|
    ansible.playbook = "site.yml"
  end
```

Vagrant generates the inventory for you, with the three nodes.

## Everyday commands

```bash
vagrant status               # state of every machine
vagrant up node1             # start only one
vagrant ssh node2
vagrant halt                 # shut down, keep the disks
vagrant provision            # run the provisioners again
vagrant reload --provision   # restart after changing the Vagrantfile
vagrant snapshot save clean  # save a restore point
vagrant snapshot restore clean
vagrant destroy -f           # delete everything
```

## Tips

- Commit the `Vagrantfile` to Git: it is the documentation of your lab.
- `/vagrant` inside each VM is a shared folder with the project directory.
- If `vagrant up` fails with a network error, run `VBoxManage list hostonlyifs` and check the host-only interface exists.
- For containers instead of VMs use [Docker](https://www.itwonderlab.com/docker/); for cloud servers use [Terraform](https://www.itwonderlab.com/terraform/).
