Vagrant
Reproducible development environments - VM lifecycle, multi-machine setups, provisioning, and snapshots.
Vagrant Basics
vagrant init hashicorp/bionic64
# Start VM (downloads box if needed)
vagrant up
# SSH into running VM
vagrant ssh
# Halt VM (graceful shutdown)
vagrant halt
# Destroy VM (remove entirely)
vagrant destroy -f
# Restart VM
vagrant reload
# Re-provision without restart
vagrant provision
# Check status
vagrant status
Current machine states: default running (virtualbox)
# List installed boxes
vagrant box list
# Add box manually
vagrant box add generic/rocky9
# Update box
vagrant box update
# Remove old box
vagrant box remove hashicorp/bionic64 --box-version 202301.01.0
# Prune old versions
vagrant box prune
MUSCLE MEMORY: vagrant up && vagrant ssh — start and connect.
Vagrantfile Configuration
Vagrant.configure("2") do |config|
config.vm.box = "generic/rocky9"
config.vm.hostname = "lab-01"
config.vm.network "private_network", ip: "192.168.56.10"
config.vm.provider "virtualbox" do |vb|
vb.memory = 2048
vb.cpus = 2
vb.name = "lab-01"
end
end
Vagrant.configure("2") do |config|
config.vm.box = "generic/rocky9"
config.vm.define "controller" do |ctrl|
ctrl.vm.hostname = "controller"
ctrl.vm.network "private_network", ip: "192.168.56.10"
ctrl.vm.provider "virtualbox" do |vb|
vb.memory = 1024
end
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.#{10 + i}"
node.vm.provider "virtualbox" do |vb|
vb.memory = 2048
end
end
end
end
Vagrant.configure("2") do |config|
config.vm.box = "generic/rocky9"
# Forward guest 80 to host 8080
config.vm.network "forwarded_port", guest: 80, host: 8080
# Synced folder
config.vm.synced_folder "./app", "/opt/app"
# Disable default share
config.vm.synced_folder ".", "/vagrant", disabled: true
end
Provisioning
Vagrant.configure("2") do |config|
config.vm.box = "generic/rocky9"
# Inline shell
config.vm.provision "shell", inline: <<-SHELL
dnf update -y
dnf install -y vim htop
SHELL
# External script
config.vm.provision "shell", path: "scripts/setup.sh"
end
Vagrant.configure("2") do |config|
config.vm.box = "generic/rocky9"
config.vm.provision "ansible" do |ansible|
ansible.playbook = "ansible/site.yml"
ansible.inventory_path = "ansible/inventory"
ansible.extra_vars = { env: "dev" }
ansible.verbose = "v"
end
end
USE CASE: Vagrant for local dev/test environments. Terraform for production infrastructure.
Snapshots
# Save named snapshot
vagrant snapshot save clean-state
# List snapshots
vagrant snapshot list
# Restore snapshot
vagrant snapshot restore clean-state
# Delete snapshot
vagrant snapshot delete clean-state
# Quick push/pop (stack-based)
vagrant snapshot push
vagrant snapshot pop
PATTERN: Snapshot before risky changes. Restore instead of re-provisioning.
Quick Reference
| Task | Command |
|---|---|
Initialize Vagrantfile |
|
Start VM |
|
SSH into VM |
|
Halt VM |
|
Destroy VM |
|
Show status |
|
Re-provision |
|
Reload (restart + provision) |
|
List boxes |
|
Remove box |
|
Snapshot save |
|
Snapshot restore |
|
Global status |
|