| name | vagrant |
| description | Comprehensive guide for developing with Vagrant, including Vagrantfile configuration, custom boxes, providers (VirtualBox, VMware, Hyper-V, libvirt, AWS), provisioners (Ansible, Chef, Puppet), multi-machine setups, networking, synced folders, plugins, and troubleshooting. |
| metadata | {"author":"mte90","version":"1.0.0","tags":["vagrant","virtualization","devops","development-environment","virtualbox","infrastructure","ansible"]} |
Vagrant Development
Complete guide for managing virtual machine environments with Vagrant.
Overview
Vagrant is a tool for building and managing virtual machine environments in a single, consistent workflow.
Key Characteristics:
- Reproducible environments
- Multiple providers (VirtualBox, VMware, Docker)
- Provisioners (Shell, Ansible, Chef, Puppet)
- Multi-machine support
- Portable boxes
Installation
Install Vagrant
brew install hashicorp/tap/hashicorp-vagrant
curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add -
sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main"
sudo apt-get update && sudo apt-get install vagrant
choco install vagrant
Install Provider
vagrant plugin install vagrant-vmware-desktop
vagrant plugin install vagrant-libvirt
Basic Vagrantfile
Minimal Configuration
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/focal64"
config.vm.hostname = "myvm"
config.vm.provider "virtualbox" do |vb|
vb.memory = "2048"
vb.cpus = 2
end
end
Complete Configuration
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/focal64"
config.vm.box_version = ">= 202310.0.0"
config.vm.hostname = "dev-environment"
config.vm.network "private_network", ip: "192.168.33.10"
config.vm.network "forwarded_port", guest: 80, host: 8080
config.vm.network "forwarded_port", guest: 443, host: 8443
config.vm.synced_folder "./app", "/var/www/html"
config.vm.synced_folder "./data", "/data", disabled: false
config.vm.provider "virtualbox" do |vb|
vb.memory = "4096"
vb.cpus = 2
vb.name = "my-dev-vm"
vb.gui = false
vb.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]
vb.customize ["modifyvm", :id, "--ioapic", "on"]
end
config.vm.provision "shell", inline: <<-SHELL
apt-get update
apt-get install -y apache2 mysql-server php
SHELL
config.vm.provision "ansible" do |ansible|
ansible.playbook = "provisioning/playbook.yml"
ansible.become = true
end
end
Common Commands
vagrant init ubuntu/focal64
vagrant up
vagrant ssh
vagrant halt
vagrant reload
vagrant destroy
vagrant suspend
vagrant resume
vagrant status
vagrant global-status
vagrant box list
vagrant box add ubuntu/focal64
vagrant box remove ubuntu/focal64
vagrant box update
vagrant box outdated
vagrant plugin list
vagrant plugin install vagrant-vbguest
vagrant plugin uninstall vagrant-vbguest
vagrant validate
vagrant ssh-config
vagrant package --output my-custom.box
Providers
VirtualBox Provider
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/focal64"
config.vm.provider "virtualbox" do |vb|
vb.name = "my-vm"
vb.gui = false
vb.memory = 4096
vb.cpus = 2
vb.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]
vb.customize ["modifyvm", :id, "--natdnsproxy1", "on"]
vb.customize ["modifyvm", :id, "--ioapic", "on"]
vb.customize ["modifyvm", :id, "--pae", "on"]
vb.customize ["modifyvm", :id, "--vram", "128"]
vb.customize ["modifyvm", :id, "--accelerate3d", "on"]
vb.customize ["storagectl", :id, "--name", "SATA Controller", "--ahci", "on"]
vb.customize ["modifyvm", :id, "--nictype1", "virtio"]
vb.customize ["modifyvm", :id, "--clipboard", "bidirectional"]
vb.customize ["modifyvm", :id, "--draganddrop", "bidirectional"]
end
end
VMware Provider
Vagrant.configure("2") do |config|
config.vm.box = "bento/ubuntu-22.04"
config.vm.provider "vmware_fusion" do |vmw|
vmw.vmx["memsize"] = "4096"
vmw.vmx["numvcpus"] = "4"
vmw.vmx["vhv.enable"] = "TRUE"
vmw.linked_clone = true
vmw.gui = false
end
config.vm.provider "vmware_workstation" do |vmw|
vmw.vmx["memsize"] = "4096"
vmw.vmx["numvcpus"] = "4"
end
end
Hyper-V Provider
Vagrant.configure("2") do |config|
config.vm.box = "microsoft/windows-server-2022"
config.vm.provider "hyperv" do |hv|
hv.memory = 4096
hv.maxmemory = 8192
hv.cpus = 2
hv.enable_virtualization_extensions = true
hv.enable_checkpoints = true
hv.vmname = "dev-vm"
hv.vlan_id = 100
hv.ip_address_timeout = 180
end
end
libvirt Provider
Vagrant.configure("2") do |config|
config.vm.box = "generic/ubuntu2204"
config.vm.provider :libvirt do |libvirt|
libvirt.cpus = 4
libvirt.memory = 4096
libvirt.driver = "kvm"
libvirt.cpu_mode = "host-passthrough"
libvirt.disk_bus = "virtio"
libvirt.disk_driver :cache => "none", :io => "native"
libvirt.video_type = "qxl"
libvirt.video_vram = "128"
libvirt.interface_type = "bridge"
libvirt.interface_source = "br0"
end
end
AWS Provider
Vagrant.configure("2") do |config|
config.vm.box = "aws"
config.vm.provider :aws do |aws, override|
override.ssh.username = "ec2-user"
override.ssh.private_key_path = "~/.ssh/my-key.pem"
aws.access_key_id = ENV['AWS_ACCESS_KEY_ID']
aws.secret_access_key = ENV['AWS_SECRET_ACCESS_KEY']
aws.region = "us-east-1"
aws.ami = "ami-0c55b159cbfafe1f0"
aws.instance_type = "t3.medium"
aws.keypair_name = "my-key"
aws.security_groups = ["default"]
aws.tags = {
'Name' => 'vagrant-dev',
'Environment' => 'development'
}
aws.block_device_mappings = [{
device_name: '/dev/sda1',
ebs: {
volume_size: 50,
volume_type: 'gp3',
delete_on_termination: true
}
}]
end
end
DigitalOcean Provider
Vagrant.configure("2") do |config|
config.vm.box = "digitalocean"
config.vm.provider :digital_ocean do |provider|
provider.access_token = ENV['DIGITALOCEAN_ACCESS_TOKEN']
provider.ssh_key_id = "12345678"
provider.image = "ubuntu-22-04-x64"
provider.size = "s-2vcpu-4gb"
provider.region = "nyc3"
provider.ssh_username = "root"
provider.private_networking = true
provider.tags = ["vagrant", "development"]
end
end
Provisioning
Shell Provisioner
Vagrant.configure("2") do |config|
config.vm.provision "shell", inline: <<-SHELL
apt-get update
apt-get install -y nginx
SHELL
config.vm.provision "shell", path: "scripts/setup.sh"
config.vm.provision "shell", path: "scripts/setup.sh",
args: ["--verbose", "--env", "development"]
config.vm.provision "shell", path: "scripts/setup.sh",
env: {
"APP_ENV" => "development",
"DB_HOST" => "localhost"
}
config.vm.provision "shell", path: "scripts/setup.sh",
privileged: false
config.vm.define "web" do |web|
web.vm.provision "shell", inline: "echo 'Web server'"
end
end
Ansible Provisioner
Vagrant.configure("2") do |config|
config.vm.provision "ansible" do |ansible|
ansible.playbook = "provisioning/playbook.yml"
ansible.inventory_path = "provisioning/inventory"
ansible.verbose = "v"
ansible.become = true
ansible.extra_vars = {
http_port: 80,
db_host: "localhost"
}
ansible.tags = ["web", "nginx"]
ansible.skip_tags = ["db"]
ansible.vault_password_file = "~/.vault_pass"
ansible.roles_path = "provisioning/roles"
ansible.galaxy_role_file = "provisioning/requirements.yml"
end
end
Ansible Local (runs on guest)
Vagrant.configure("2") do |config|
config.vm.provision "ansible_local" do |ansible|
ansible.playbook = "playbook.yml"
ansible.install_mode = "pip"
ansible.version = "2.14.0"
ansible.verbose = "v"
ansible.become = true
ansible.galaxy_file = "requirements.yml"
ansible.galaxy_roles_path = "roles"
end
end
Chef Provisioner
Vagrant.configure("2") do |config|
config.vm.provision "chef_solo" do |chef|
chef.cookbooks_path = "cookbooks"
chef.roles_path = "roles"
chef.add_recipe "webserver::default"
chef.add_recipe "database::default"
chef.json = {
webserver: {
port: 80,
docroot: "/var/www/html"
}
}
end
end
Puppet Provisioner
Vagrant.configure("2") do |config|
config.vm.provision "puppet_apply" do |puppet|
puppet.manifests_path = "manifests"
puppet.manifest_file = "site.pp"
puppet.module_path = "modules"
puppet.facter = {
"environment" => "development",
"server_role" => "web"
}
puppet.options = ["--verbose", "--debug"]
end
end
Docker Provisioner
Vagrant.configure("2") do |config|
config.vm.provision "docker" do |d|
d.pull_images "nginx:latest"
d.pull_images "postgres:14"
d.run "nginx",
image: "nginx:latest",
args: "-p 80:80 -v /vagrant/nginx.conf:/etc/nginx/nginx.conf"
d.run "postgres",
image: "postgres:14",
args: "-e POSTGRES_PASSWORD=secret -p 5432:5432"
end
end
Multi-Machine Setup
Basic Multi-Machine
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/focal64"
config.vm.define "web" do |web|
web.vm.hostname = "web"
web.vm.network "private_network", ip: "192.168.33.10"
web.vm.network "forwarded_port", guest: 80, host: 8080
web.vm.provider "virtualbox" do |vb|
vb.memory = "2048"
end
web.vm.provision "shell", inline: "apt-get install -y nginx"
end
config.vm.define "db" do |db|
db.vm.hostname = "db"
db.vm.network "private_network", ip: "192.168.33.20"
db.vm.provider "virtualbox" do |vb|
vb.memory = "4096"
end
db.vm.provision "shell", inline: "apt-get install -y postgresql"
end
end
Complex Multi-Machine with Dependencies
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/focal64"
config.vm.define "loadbalancer", primary: true do |lb|
lb.vm.hostname = "lb"
lb.vm.network "private_network", ip: "192.168.33.10"
lb.vm.network "forwarded_port", guest: 80, host: 8080
lb.vm.provider "virtualbox" do |vb|
vb.memory = "1024"
end
lb.vm.provision "shell", inline: <<-SHELL
apt-get update
apt-get install -y haproxy
SHELL
end
(1..3).each do |i|
config.vm.define "web#{i}" do |web|
web.vm.hostname = "web#{i}"
web.vm.network "private_network", ip: "192.168.33.#{20 + i}"
web.vm.provider "virtualbox" do |vb|
vb.memory = "2048"
end
web.vm.provision "shell", inline: <<-SHELL
apt-get update
apt-get install -y nginx
echo "Web Server #{i}" > /var/www/html/index.html
SHELL
web.vm.provision "shell", run: "never" do |s|
s.inline = "echo 'Web#{i} ready'"
end
end
end
config.vm.define "database" do |db|
db.vm.hostname = "db"
db.vm.network "private_network", ip: "192.168.33.50"
db.vm.provider "virtualbox" do |vb|
vb.memory = "4096"
end
db.vm.provision "shell", inline: <<-SHELL
apt-get update
apt-get install -y postgresql
systemctl start postgresql
SHELL
end
end
Control Commands
vagrant up
vagrant up web
vagrant up web db
vagrant ssh web
vagrant provision web
vagrant reload web
vagrant destroy web
Networking
Private Networks
Vagrant.configure("2") do |config|
config.vm.network "private_network", ip: "192.168.33.10"
config.vm.network "private_network",
ip: "192.168.33.10",
netmask: "255.255.255.0"
config.vm.network "private_network", type: "dhcp"
config.vm.network "private_network",
ip: "10.0.0.10",
virtualbox__intnet: "internal_network"
end
Public Networks (Bridged)
Vagrant.configure("2") do |config|
config.vm.network "public_network",
bridge: "en0: Wi-Fi (AirPort)"
config.vm.network "public_network",
bridge: "en0",
ip: "192.168.1.100"
config.vm.network "public_network"
end
Port Forwarding
Vagrant.configure("2") do |config|
config.vm.network "forwarded_port", guest: 80, host: 8080
config.vm.network "forwarded_port",
guest: 80,
host: 8080,
auto_correct: true
config.vm.network "forwarded_port",
guest: 53,
host: 1053,
protocol: "udp"
config.vm.network "forwarded_port", guest: 80, host: 8080
config.vm.network "forwarded_port", guest: 443, host: 8443
config.vm.network "forwarded_port", guest: 3306, host: 3306
end
Synced Folders
VirtualBox Shared Folders (Default)
Vagrant.configure("2") do |config|
config.vm.synced_folder "./app", "/var/www/html"
config.vm.synced_folder ".", "/vagrant", disabled: true
config.vm.synced_folder "./app", "/var/www/html",
owner: "www-data",
group: "www-data",
mount_options: ["dmode=775", "fmode=664"]
end
NFS (Better Performance)
Vagrant.configure("2") do |config|
config.vm.synced_folder "./app", "/var/www/html",
type: "nfs",
nfs_udp: false,
mount_options: [
"nfsvers=3",
"tcp",
"rsize=32768",
"wsize=32768"
]
end
RSync
Vagrant.configure("2") do |config|
config.vm.synced_folder "./app", "/var/www/html",
type: "rsync",
rsync__auto: true,
rsync__exclude: [".git/", "node_modules/", "*.log"],
rsync__args: ["--verbose", "--archive", "--delete", "-z"]
end
SMB (Windows)
Vagrant.configure("2") do |config|
config.vm.synced_folder "./app", "/var/www/html",
type: "smb",
smb_host: "127.0.0.1",
smb_username: ENV['USER'],
smb_password: ENV['SMB_PASSWORD']
end
Custom Boxes
Packaging a Box
vagrant package --base my-configured-vm --output my-custom.box
vagrant package --base my-vm --output my.box --vagrantfile Vagrantfile.template
vagrant package --base my-vm --output my.box --include README.md,metadata.json
metadata.json
{
"name": "myorg/ubuntu-custom",
"description": "Custom Ubuntu 20.04 with pre-installed tools",
"versions": [
{
"version": "1.0.0",
"providers": [
{
"name": "virtualbox",
"url": "https://example.com/boxes/ubuntu-custom-1.0.0.box",
"checksum": "sha256:abc123...",
"checksum_type": "sha256"
}
]
}
]
}
Adding and Using Custom Boxes
vagrant box add myorg/ubuntu-custom ./my-custom.box
vagrant box add myorg/ubuntu-custom https://example.com/my-custom.box
vagrant box list
vagrant box update --box myorg/ubuntu-custom
vagrant box remove myorg/ubuntu-custom
Publishing to Vagrant Cloud
vagrant cloud auth login
vagrant cloud publish myorg/ubuntu-custom 1.0.0 \
--description "Custom Ubuntu with development tools" \
--provider virtualbox \
--file ./my-custom.box
Plugins
Installing Plugins
vagrant plugin install vagrant-vbguest
vagrant plugin install vagrant-vbguest --plugin-version 0.21.0
vagrant plugin list
vagrant plugin update vagrant-vbguest
vagrant plugin uninstall vagrant-vbguest
Useful Plugins
vagrant plugin install vagrant-vbguest
vagrant plugin install vagrant-hostmanager
vagrant plugin install vagrant-disksize
vagrant plugin install vagrant-snapshot
vagrant plugin install vagrant-cachier
Plugin Configuration
config.vbguest.auto_update = true
config.vbguest.no_remote = true
config.hostmanager.enabled = true
config.hostmanager.manage_host = true
config.hostmanager.manage_guest = true
config.disksize.size = '50GB'
Triggers
Basic Triggers
Vagrant.configure("2") do |config|
config.trigger.before :up do |trigger|
trigger.name = "Before Up"
trigger.info = "Starting VM..."
end
config.trigger.after :up do |trigger|
trigger.name = "After Up"
trigger.run = {inline: "echo 'VM is ready!'"}
end
config.trigger.before :destroy do |trigger|
trigger.name = "Confirm Destroy"
trigger.ask = "Are you sure you want to destroy?"
end
end
Advanced Triggers
Vagrant.configure("2") do |config|
config.trigger.after :up do |trigger|
trigger.run = {
inline: "echo 'VM IP:' && vagrant ssh -c 'ip addr show eth1'"
}
end
config.trigger.after :provision do |trigger|
trigger.run_remote = {
inline: "systemctl status nginx"
}
end
config.vm.define "web" do |web|
web.trigger.after :up do |trigger|
trigger.info = "Web server is up!"
end
end
end
Troubleshooting
Common Errors
SSH Timeout
Vagrant.configure("2") do |config|
config.ssh.timeout = 120
config.ssh.insert_key = false
config.vm.provider "virtualbox" do |vb|
vb.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]
end
end
Network Issues
vagrant ssh -c "ip addr show"
vagrant ssh -c "cat /etc/network/interfaces"
vagrant reload
VBoxManage list natnets
VBoxManage list hostonlyifs
Synced Folder Permission Denied
config.vm.synced_folder "./app", "/var/www/html",
owner: "vagrant",
group: "vagrant",
mount_options: ["dmode=775", "fmode=664"]
Box Download Issues
rm -rf ~/.vagrant.d/tmp/*
vagrant box add ubuntu/focal64 --box-version 202310.0.0
export VAGRANT_SERVER_URL="https://vagrantcloud.com"
Debug Mode
VAGRANT_LOG=debug vagrant up
VAGRANT_LOG=info vagrant up
VAGRANT_LOG=debug VAGRANT_DEFAULT_PROVIDER=virtualbox vagrant up
Reset Environment
vagrant destroy -f
vagrant box remove ubuntu/focal64
rm -rf .vagrant
rm -rf ~/.vagrant.d/data
vagrant up
Performance Optimization
VirtualBox Optimization
Vagrant.configure("2") do |config|
config.vm.provider "virtualbox" do |vb|
vb.memory = 4096
vb.cpus = 2
vb.pae = true
vb.customize ["storagectl", :id, "--name", "SATA Controller", "--ahci", "on"]
vb.customize ["storageattach", :id, "--storagectl", "SATA Controller",
"--type", "hdd", "--nonrotational", "on"]
vb.customize ["modifyvm", :id, "--nictype1", "virtio"]
vb.customize ["modifyvm", :id, "--audio", "none"]
end
config.vm.synced_folder "./app", "/app", type: "nfs"
end
Parallel Operations
Vagrant.configure("2") do |config|
config.vm.define "web"
config.vm.define "db"
config.vm.provision "shell", inline: "apt-get update", run: "always"
end
Best Practices
- Version control your Vagrantfile
- Use specific box versions for reproducibility
- Use provisioners for repeatable setup
- Enable auto_correct for port forwarding
- Use triggers for automation hooks
- Document custom boxes with README
- Test multi-machine setups thoroughly
- Use NFS for better synced folder performance
- Keep Vagrant updated
- Clean up unused boxes regularly
Resources
Quick Reference
Common Vagrantfile Patterns
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/focal64"
config.vm.network "private_network", ip: "192.168.33.10"
config.vm.synced_folder ".", "/vagrant"
end
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/focal64"
config.vm.provision "shell", path: "setup.sh"
end
Vagrant.configure("2") do |config|
config.vm.define "web"
config.vm.define "db"
end
Common Commands
vagrant up
vagrant ssh
vagrant halt
vagrant destroy
vagrant reload
vagrant provision
vagrant status
vagrant global-status
vagrant box list
vagrant plugin list