How to Set Up Vagrant and VirtualBox on RHEL 7

Vagrant is an open-source tool by HashiCorp that automates the creation, configuration, and management of virtualized development environments. Combined with VirtualBox as a hypervisor backend, Vagrant allows developers and operations engineers on RHEL 7 to spin up reproducible Linux (or Windows) virtual machines with a single command: vagrant up. This eliminates the “works on my machine” problem by encoding the entire environment — base OS, packages, network, shared folders, and provisioning scripts — in a version-controlled Vagrantfile. This tutorial covers adding the VirtualBox yum repository, installing VirtualBox, installing Vagrant from the HashiCorp repository, creating and connecting to a first VM, mastering the Vagrantfile, and configuring multi-machine environments.

Prerequisites

  • RHEL 7 host with hardware virtualization support (Intel VT-x or AMD-V enabled in BIOS/UEFI)
  • Root or sudo access
  • At least 4 GB of RAM free for guest VMs
  • Active RHEL subscription or configured yum repositories
  • Kernel headers and development tools installed (yum install -y kernel-devel kernel-headers gcc make)
  • Internet access or an internal mirror containing the VirtualBox and HashiCorp repositories

Step 1: Verify Hardware Virtualization

Before installing VirtualBox, confirm that hardware virtualization is available and not already consumed by another hypervisor such as KVM:

# Check for Intel VT-x or AMD-V flags in the CPU
egrep -c '(vmx|svm)' /proc/cpuinfo
# Output > 0 means virtualization is available

# Confirm no conflicting KVM modules are loaded
lsmod | grep kvm
# If kvm_intel or kvm_amd appear, either remove them or use KVM instead of VirtualBox
# sudo modprobe -r kvm_intel kvm

Step 2: Install Required Build Dependencies

VirtualBox compiles kernel modules during installation, which requires the kernel development headers and GCC toolchain:

sudo yum install -y kernel-devel kernel-headers dkms gcc make perl
sudo yum install -y "kernel-devel-$(uname -r)"

If the kernel-devel package for the exact running kernel is not available in the default repositories, you can find it on the RHEL subscription portal or the CentOS Vault mirror.

Step 3: Add the VirtualBox yum Repository

Oracle provides an official yum repository for VirtualBox. Add it to your system:

sudo tee /etc/yum.repos.d/virtualbox.repo <<'EOF'
[virtualbox]
name=Oracle Linux / RHEL / CentOS-$releasever / $basearch - VirtualBox
baseurl=https://download.virtualbox.org/virtualbox/rpm/el/$releasever/$basearch
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://www.virtualbox.org/download/oracle_vbox_2016.asc
EOF

# Import the GPG key manually to avoid warnings
sudo rpm --import https://www.virtualbox.org/download/oracle_vbox_2016.asc

# Verify the repo is recognized
yum repolist | grep virtualbox

Step 4: Install VirtualBox

# List available VirtualBox versions
yum list available | grep VirtualBox

# Install the latest VirtualBox 7.0 (or the version appropriate for your use case)
sudo yum install -y VirtualBox-7.0

# The postinstall script will compile and load the kernel modules automatically
# Verify the modules loaded correctly
sudo /sbin/vboxconfig

Expected output from /sbin/vboxconfig:

vboxdrv.sh: Stopping VirtualBox services.
vboxdrv.sh: Starting VirtualBox services.
vboxdrv.sh: Building VirtualBox kernel modules.
vboxdrv.sh: done.

Add your current user to the vboxusers group to allow non-root access to VirtualBox:

sudo usermod -aG vboxusers $USER
# Log out and back in for the group change to take effect

Step 5: Add the HashiCorp yum Repository and Install Vagrant

HashiCorp maintains an official yum repository for RHEL-based systems. This is the safest way to install Vagrant and receive updates:

sudo tee /etc/yum.repos.d/hashicorp.repo <<'EOF'
[hashicorp]
name=HashiCorp Stable - $basearch
baseurl=https://rpm.releases.hashicorp.com/RHEL/$releasever/$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://rpm.releases.hashicorp.com/gpg
EOF

# Import the HashiCorp GPG key
sudo rpm --import https://rpm.releases.hashicorp.com/gpg

# Install Vagrant
sudo yum install -y vagrant

# Verify installation
vagrant --version
# Vagrant 2.x.x

Step 6: Initialize and Start Your First VM

Create a working directory for your project and initialize a Vagrantfile using a standard Ubuntu 20.04 (Focal Fossa) base box:

mkdir ~/vagrant-demo && cd ~/vagrant-demo

# Initialize with the ubuntu/focal64 box from Vagrant Cloud
vagrant init ubuntu/focal64

# This creates a Vagrantfile in the current directory
# Start the VM (downloads the box on first run — ~600 MB)
vagrant up

During vagrant up, you will see Vagrant download the base box (if not already cached), import it into VirtualBox, boot it, and apply any configured provisioning. Box downloads are cached in ~/.vagrant.d/boxes/ so subsequent vagrant up commands for the same box are near-instant.

Step 7: Connect to the VM with vagrant ssh

# SSH into the running VM (no password needed — Vagrant handles key exchange)
vagrant ssh

# Inside the VM
uname -a
# Linux ubuntu-focal ...

cat /etc/os-release
# Ubuntu 20.04 LTS

# Exit the VM shell
exit

Vagrant automatically configures SSH port forwarding and injects an insecure (development-only) keypair. The host key and connection details are in .vagrant/machines/default/virtualbox/.

Step 8: Mastering the Vagrantfile

The Vagrantfile is a Ruby DSL file that fully describes your VM configuration. Here is a comprehensive example with common options:

Vagrant.configure("2") do |config|

  # Base box
  config.vm.box = "ubuntu/focal64"
  config.vm.box_version = ">= 20240101.0.0"
  config.vm.hostname = "dev-server"

  # Network — forward host port 8080 to guest port 80
  config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"

  # Private network — assign a static IP (host-only adapter)
  config.vm.network "private_network", ip: "192.168.56.10"

  # Synced folder — share project code into the VM
  config.vm.synced_folder "./app", "/var/www/app",
    owner: "vagrant", group: "vagrant"

  # VirtualBox-specific provider settings
  config.vm.provider "virtualbox" do |vb|
    vb.name   = "dev-server"
    vb.memory = "2048"   # MB
    vb.cpus   = 2
    vb.gui    = false    # headless mode
    # Enable nested virtualization if needed
    # vb.customize ["modifyvm", :id, "--nested-hw-virt", "on"]
  end

  # Shell provisioner — runs once on first vagrant up
  config.vm.provision "shell", inline: <<-SHELL
    apt-get update -y
    apt-get install -y nginx git curl
    systemctl enable nginx
    systemctl start nginx
    echo "Provisioning complete"
  SHELL

end

Apply changes to a running VM:

# Re-run provisioners on an already-running VM
vagrant provision

# Reload (restart) the VM and re-apply Vagrantfile changes
vagrant reload

# Reload and re-run provisioners
vagrant reload --provision

Step 9: VM Lifecycle — halt, suspend, destroy

# Gracefully shut down the VM (preserves disk state)
vagrant halt

# Suspend to disk (saves RAM state, fast resume)
vagrant suspend
vagrant resume

# Delete the VM entirely (frees disk space; Vagrantfile is retained)
vagrant destroy

# Destroy without confirmation prompt
vagrant destroy -f

# Check status of all VMs in the current directory
vagrant status

# Check status of all Vagrant VMs on the host
vagrant global-status

Step 10: Multi-Machine Environments

Vagrant supports defining multiple VMs in a single Vagrantfile, enabling you to replicate complex environments — for example, a load balancer, two web servers, and a database — on a single RHEL 7 development host:

Vagrant.configure("2") do |config|

  config.vm.box = "ubuntu/focal64"

  # Database server
  config.vm.define "db" do |db|
    db.vm.hostname = "db-server"
    db.vm.network "private_network", ip: "192.168.56.20"
    db.vm.provider "virtualbox" do |vb|
      vb.memory = "1024"
      vb.cpus   = 1
    end
    db.vm.provision "shell", inline: <<-SHELL
      apt-get update -y
      apt-get install -y postgresql
      systemctl enable postgresql
    SHELL
  end

  # Web application servers (2 instances using a loop)
  (1..2).each do |i|
    config.vm.define "web#{i}" do |web|
      web.vm.hostname = "web-server-#{i}"
      web.vm.network "private_network", ip: "192.168.56.#{10 + i}"
      web.vm.provider "virtualbox" do |vb|
        vb.memory = "512"
        vb.cpus   = 1
      end
      web.vm.provision "shell", inline: <<-SHELL
        apt-get update -y
        apt-get install -y nginx
        echo "web#{i}" > /var/www/html/index.html
      SHELL
    end
  end

end

Manage individual machines by name:

# Start only the db machine
vagrant up db

# SSH into web1
vagrant ssh web1

# Halt all machines
vagrant halt

# Destroy a specific machine
vagrant destroy web2 -f

Vagrant and VirtualBox together on RHEL 7 deliver a powerful, reproducible development platform that any team member can replicate in minutes. By encoding your environment in a versioned Vagrantfile, you eliminate configuration drift between development, staging, and production-like test environments. For teams practicing infrastructure-as-code, the Vagrantfile becomes the single authoritative description of the local development environment — committed to version control, reviewed like application code, and reproduced with a single command on any RHEL 7 workstation or server with hardware virtualization support.