Open-source tool for building and managing portable, reproducible virtual development environments using providers like VirtualBox, libvirt, and Hyper-V.

Addresses below are RFC 5737 documentation ranges or placeholders - swap in your own.

Table of Contents#

  1. Overview
  2. How Vagrant Works
  3. Installation
  4. Vagrantfile Configuration
  5. Multi-Machine Environments
  6. Provisioning
  7. Networking
  8. Synced Folders
  9. Box Management
  10. CLI Reference
  11. Troubleshooting
  12. See Also
  13. Sources

1. Overview#

Vagrant is an open-source tool by HashiCorp for building and managing virtualized development environments. It eliminates "it works on my machine" problems by providing consistent, reproducible environments defined as code.

Key features:

  • Provider-agnostic - works with VirtualBox, libvirt/KVM, VMware, Hyper-V, Docker, and more
  • Infrastructure as code - environments defined in a Vagrantfile (Ruby DSL)
  • Provisioner support - shell scripts, Ansible, Puppet, Chef, Salt
  • Multi-machine - define and orchestrate multiple VMs in a single Vagrantfile
  • Box ecosystem - pre-built base images from Vagrant Cloud

2. How Vagrant Works#

Vagrant uses three core concepts:

  • Boxes - base images (package format) used to create VMs. Each box is a pre-configured OS image.
  • Vagrantfile - Ruby configuration file that defines the VM(s), including box, networking, provisioning, and provider-specific settings.
  • Providers - the virtualization backend (VirtualBox, libvirt, etc.) that actually runs the VM.

Workflow: vagrant init creates a Vagrantfile, vagrant up builds and starts the VM(s), vagrant ssh connects to them.


3. Installation#

3.1 Installing Vagrant#

# Debian/Ubuntu
wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.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 vagrant

# Fedora/RHEL
sudo dnf install -y dnf-plugins-core
sudo dnf config-manager --add-repo https://rpm.releases.hashicorp.com/fedora/hashicorp.repo
sudo dnf install vagrant

# Arch Linux
sudo pacman -S vagrant

Also install a provider (e.g., VirtualBox, libvirt):

# libvirt provider (recommended for KVM users)
vagrant plugin install vagrant-libvirt

3.2 Initializing a Project#

mkdir my-project && cd my-project
vagrant init ubuntu/jammy64
vagrant up

4. Vagrantfile Configuration#

4.1 Basic Vagrantfile#

Vagrant.configure("2") do |config|
  # Base box
  config.vm.box = "ubuntu/jammy64"

  # Hostname
  config.vm.hostname = "dev-server"

  # Provider-specific settings
  config.vm.provider "virtualbox" do |vb|
    vb.memory = "2048"
    vb.cpus = 2
    vb.name = "dev-server"
  end

  # libvirt provider settings
  config.vm.provider "libvirt" do |lv|
    lv.memory = 2048
    lv.cpus = 2
  end
end

4.2 Provider Selection#

# Use a specific provider
vagrant up --provider=libvirt
vagrant up --provider=virtualbox

# Set default provider via environment variable
export VAGRANT_DEFAULT_PROVIDER=libvirt

5. Multi-Machine Environments#

Define multiple VMs in a single Vagrantfile for complex environments:

Vagrant.configure("2") do |config|
  # Web server
  config.vm.define "web" do |web|
    web.vm.box = "ubuntu/jammy64"
    web.vm.hostname = "web-server"
    web.vm.network "private_network", ip: "192.0.2.10"
    web.vm.provider "virtualbox" do |vb|
      vb.memory = "1024"
    end
    web.vm.provision "shell", inline: <<-SHELL
      apt-get update
      apt-get install -y nginx
    SHELL
  end

  # Database server
  config.vm.define "db" do |db|
    db.vm.box = "ubuntu/jammy64"
    db.vm.hostname = "db-server"
    db.vm.network "private_network", ip: "192.0.2.11"
    db.vm.provider "virtualbox" do |vb|
      vb.memory = "2048"
    end
    db.vm.provision "shell", inline: <<-SHELL
      apt-get update
      apt-get install -y postgresql
    SHELL
  end
end

Target specific machines:

vagrant up web          # Start only the web VM
vagrant ssh db          # SSH into the db VM
vagrant halt web        # Stop only the web VM
vagrant destroy db -f   # Destroy only the db VM

6. Provisioning#

6.1 Shell Provisioner#

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

  # Inline script
  config.vm.provision "shell", inline: <<-SHELL
    apt-get update
    apt-get install -y nginx
    systemctl enable --now nginx
  SHELL

  # External script
  config.vm.provision "shell", path: "scripts/setup.sh"

  # Run as unprivileged user (not root)
  config.vm.provision "shell", inline: "echo Hello", privileged: false
end

6.2 Ansible Provisioner#

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

  # Ansible runs from the HOST machine (requires Ansible installed on host)
  config.vm.provision "ansible" do |ansible|
    ansible.playbook = "playbook.yml"
    ansible.inventory_path = "inventory"
    ansible.limit = "all"
    ansible.verbose = "v"
    # Extra variables
    ansible.extra_vars = {
      env: "development"
    }
  end
end

6.3 Ansible Local Provisioner#

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

  # Ansible runs INSIDE the guest VM (no Ansible needed on host)
  config.vm.provision "ansible_local" do |ansible|
    ansible.playbook = "playbook.yml"
    ansible.install = true   # Auto-install Ansible in the guest
  end
end

6.4 Puppet Provisioner#

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

  config.vm.provision "puppet" do |puppet|
    puppet.manifests_path = "manifests"
    puppet.manifest_file = "default.pp"
    puppet.module_path = "modules"
  end
end

6.5 Provisioning Controls#

# Run provisioners on an already running VM
vagrant provision

# Force provisioners on vagrant up (even if already provisioned)
vagrant up --provision

# Skip provisioners
vagrant up --no-provision

# Run only specific provisioners
vagrant provision --provision-with shell

7. Networking#

7.1 Port Forwarding#

config.vm.network "forwarded_port", guest: 80, host: 8080
config.vm.network "forwarded_port", guest: 443, host: 8443, protocol: "tcp"

7.2 Private Network#

# Static IP
config.vm.network "private_network", ip: "192.0.2.10"

# DHCP
config.vm.network "private_network", type: "dhcp"

7.3 Public Network (Bridged)#

# Bridged to a host interface (VM appears on the LAN)
config.vm.network "public_network", bridge: "eth0"

8. Synced Folders#

# Default: project directory synced to /vagrant in guest
# Custom synced folders:
config.vm.synced_folder "./src", "/var/www/html"
config.vm.synced_folder "./data", "/data", type: "nfs"
config.vm.synced_folder "./code", "/code", type: "rsync",
    rsync__exclude: [".git/", "node_modules/"]

# Disable the default /vagrant share
config.vm.synced_folder ".", "/vagrant", disabled: true

9. Box Management#

9.1 Creating Custom Boxes#

Package a running VM into a reusable box:

# From a VirtualBox VM
vagrant package --output my-custom.box

# Add the custom box locally
vagrant box add my-custom my-custom.box

# Use it in a Vagrantfile
# config.vm.box = "my-custom"

9.2 Box Commands#

CommandDescription
vagrant box listList all installed boxes
vagrant box add <name>Download and add a box
vagrant box updateUpdate boxes to latest version
vagrant box remove <name>Remove a box
vagrant box outdatedCheck for box updates
vagrant box pruneRemove old versions of boxes

10. CLI Reference#

10.1 General Commands#

CommandDescription
vagrant statusStatus of current Vagrant machine(s)
vagrant global-statusStatus of all active Vagrant machines
vagrant global-status --pruneRemove invalid entries from status list
vagrant versionShow Vagrant version
vagrant validateValidate the Vagrantfile syntax

10.2 VM Lifecycle#

CommandDescription
vagrant upStart and provision the environment
vagrant haltGraceful shutdown
vagrant suspendSuspend (save state to disk)
vagrant resumeResume a suspended machine
vagrant reloadHalt then up (applies Vagrantfile changes)
vagrant sshConnect via SSH
vagrant ssh-configShow SSH config (useful for direct ssh usage)
vagrant destroyRemove all traces of the machine
vagrant destroy -fForce destroy without confirmation

10.3 Debugging#

# Verbose output for troubleshooting
VAGRANT_LOG=debug vagrant up

# Show SSH connection details
vagrant ssh-config

# Check Vagrantfile syntax
vagrant validate

Troubleshooting#

IssueCauseSolution
vagrant up hangs at SSHGuest SSH server not starting, or firewall blockingCheck VAGRANT_LOG=debug vagrant up; verify box supports the provider
Box download failsNetwork issue or box not foundCheck box name on Vagrant Cloud; try vagrant box add <url> directly
Synced folder mount failsNFS not installed or firewall blockingInstall nfs-utils; for VirtualBox use type: "virtualbox" instead
Provider not foundPlugin not installedRun vagrant plugin install vagrant-libvirt (or appropriate provider)
Port forwarding not workingHost port already in useChange host port; check with ss -tlnp | grep <port>
vagrant destroy leaves artifactsProvider-specific cleanup incompleteManually remove VMs from VirtualBox/libvirt; run vagrant global-status --prune
Provisioner runs every vagrant upProvisioner not marked as run: "once"Add run: "once" to provisioner config, or use --no-provision

See Also#

Sources#