Writing a general multi-provider Vagrantfile

Vagrant is a great software that allows people to use various providers, provisioners, sync options, and more. But that often comes short if we write our project’s Vagrantfile just for default VirtualBox. Since I prefer to use libvirt provider and NFS I tend to write Vagrantfile that only support those (as they are just for myself). But lately I was writing a Vagrantfile for upcoming Fedora Developer Portal and wanted to support both Fedora users running our packages with libvirt as a default provider and everyone else as well.

The solution to the problem is easier that you would think. As Vagrantfile is just a regular Ruby file, we can use Ruby conditionals to write Vagrantfile in a more robust and general way. Here is an example of Fedora Developer Portal Vagrantfile:

# -*- mode: ruby -*-
# vi: set ft=ruby :

# Start the Jekyll server for local development on the guest:
#   cd /vagrant
#   jekyll serve --force_polling -H

Vagrant.configure(2) do |config|
  config.vm.box = "fedora-22-cloud"

  config.vm.provider :virtualbox do |virtualbox|
    config.vm.box_url = "https://download.fedoraproject.org/pub/fedora/linux/releases/22/Cloud/x86_64/Images/Fedora-Cloud-Base-Vagrant-22-20150521.x86_64.vagrant-virtualbox.box"

  config.vm.provider :libvirt do |libvirt|
    config.vm.box_url = "https://download.fedoraproject.org/pub/fedora/linux/releases/22/Cloud/x86_64/Images/Fedora-Cloud-Base-Vagrant-22-20150521.x86_64.vagrant-libvirt.box"
  end if Vagrant.has_plugin?('vagrant-libvirt')

  config.vm.network "forwarded_port", guest: 4000, host: 4000

  config.vm.synced_folder ".", "/vagrant", type: "rsync"

  config.vm.provision "shell", path: "setup.sh"

The trick to support two providers is to provide a box_url configuration option with the same or similar boxes for every provider we want to support. Since the Fedora Project now started to produce Vagrant images officially, we can just link those. Note that for any provider that does not come with the standard Vagrant installation we are using Vagrant.has_plugin? function to determine if we have the right plugin installed.

In the above example Fedora users will get the libvirt image and Mac OS users will get the VirtualBox image. This is because we switched the default provider to libvirt in Fedora (as we don’t have VirtualBox in our own repositories). The nice thing about this all is that all users are still able to use both if they want to by appending --provider option to vagrant up or by setting ENV['VAGRANT_DEFAULT_PROVIDER'] environment variable.


I wrote a complete guide on web application deployment. Ruby with Puma, Python with Gunicorn, NGINX, PostgreSQL, Redis, networking, processes, systemd, backups, and all your usual suspects.

More →