Vagrant creates and manages development virtual machines from a simple file, the Vagrantfile. One command gives every developer the same VM — same OS, same packages, same config — and another destroys it when you’re done. It’s especially handy for testing server setups (Ansible playbooks, install scripts, firewall rules) locally before running them on a real VPS.

Install

Install Vagrant from HashiCorp’s downloads or repository, plus a provider — the virtualization software that actually runs the VM:

  • VirtualBox — cross-platform, the most common default.
  • libvirt/KVM — fast on Linux (via the vagrant-libvirt plugin).
  • VMware, Hyper-V, Parallels — on their respective platforms.
  • Docker — containers instead of VMs (limited).

Apple Silicon Macs need ARM boxes and a provider such as VMware Fusion, Parallels or QEMU-based plugins.

Your first VM

mkdir ~/vm-test && cd ~/vm-test
vagrant init bento/ubuntu-24.04
vagrant up
vagrant ssh

vagrant init writes a Vagrantfile; vagrant up downloads the box (a base image) the first time and boots it; vagrant ssh logs you in.

Everyday commands:

Command Does
vagrant up Create/start the VM
vagrant ssh Log in
vagrant halt Shut down
vagrant reload Restart (and apply Vagrantfile changes)
vagrant provision Re-run provisioners
vagrant destroy -f Delete the VM
vagrant status / global-status State of VMs
vagrant snapshot save clean / restore clean Snapshots of the dev VM

A useful Vagrantfile

Vagrant.configure("2") do |config|
  config.vm.box = "bento/ubuntu-24.04"
  config.vm.hostname = "web-test"

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

  config.vm.synced_folder "./site", "/var/www/site"

  config.vm.provider "virtualbox" do |vb|
    vb.memory = 2048
    vb.cpus = 2
  end

  config.vm.provision "shell", inline: <<-SHELL
    apt-get update
    apt-get install -y nginx
  SHELL
end
  • Private network — reach the VM at a fixed IP from your machine.
  • Forwarded port — http://localhost:8080 reaches Nginx in the VM.
  • Synced folder — edit files on your laptop, serve them from the VM.
  • Provisioning runs on the first up (or with vagrant provision).

Provision with Ansible

Test the same playbook you’ll use on production servers:

  config.vm.provision "ansible" do |ansible|
    ansible.playbook = "ansible/site.yml"
    ansible.groups = { "web" => ["default"] }
  end

This is one of Vagrant’s best uses: iterate on Ansible playbooks locally, vagrant destroy && vagrant up to verify they work from scratch, then apply them to your VPS with confidence.

Multi-machine setups

Vagrant.configure("2") do |config|
  config.vm.box = "bento/ubuntu-24.04"
  %w[web db].each_with_index do |name, i|
    config.vm.define name do |node|
      node.vm.hostname = name
      node.vm.network "private_network", ip: "192.168.56.#{10 + i}"
    end
  end
end

Simulate a web server and a database server talking over a private network — e.g. to test MySQL remote access and firewall rules.

Vagrant vs alternatives

  • Docker / Dev Containers — lighter and faster for application development; Vagrant is better when you need a full OS with systemd, kernel modules or firewall testing.
  • Multipass (Canonical) — quick Ubuntu VMs with one command; fewer features.
  • A cheap VPS — the real environment, reachable from anywhere; ideal for testing network-facing setups (DNS, TLS, mail). A small KVM VPS can be reinstalled from the control panel in minutes, which makes it a great disposable lab.

Tips

  • Commit the Vagrantfile (and provisioning scripts) to your project repository.
  • Pin box versions (config.vm.box_version) for reproducibility.
  • Use vagrant destroy freely — the point is that VMs are disposable.

Related: infrastructure as code and Packer, which builds boxes and images from code.

  • Vagrant
  • Virtualization
  • Development