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-libvirtplugin). - 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:8080reaches Nginx in the VM. - Synced folder — edit files on your laptop, serve them from the VM.
- Provisioning runs on the first
up(or withvagrant 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 destroyfreely — the point is that VMs are disposable.
Related: infrastructure as code and Packer, which builds boxes and images from code.