Vagrant Logo

Single Vagrant for multiple projects

How we could single Vagrant box setup for multiple projects

Here we will show you how you can easily and fast, setup multiple working environments, using single Vagrant machine (from single box).

What is Vagrant

[dropcap]V[/dropcap]agrant is a Hashicorp product, which “is a tool for building and managing virtual machine environments in a single workflow“.

With it, you can emulate pretty much every server environment, you or your team is using for production.

Vagrant is the perfect solution for local development out there, and even if there are others like Docker for instance, they posses way too many flaws compared to what you could achieve with Vagrant.

Here is what you will achieve in the end:

Vagrant could run on every major OS (and few smaller ones)

What you need in order to have Vagrant up and running locally:

  • Processor which supports virtualization
  • VirtualBox, VMware, AWS (only one of these)

Not much huh?!

Most common configuration used out there is VartualBox + Vagrant.

Vagrant is a free software as well as VirtualBox – you can download these on whatever your preferred operating system is.

How to install Vagrant

As this document scope does not cover the details about how to install Vagrant, we will focus on a very basic explanation.

For more detailed explanation you could refer to official documentation located here: Vagrant – getting started.

Vagrant works with so called boxes – they are from different providers (you could create your own if you want) and they contain different pre-installed configurations (usually, but not only, Linux based).

After installing VBox and Vagrant you need to initialize project in directory of your choice with the following (in this case we will use bionic64 from Hashicorp which is for VBox provider and it is based on Ubuntu Bionic Beaver)

$ vagrant init hashicorp/bionic64
$ vagrant up

After executing the commands above, Vagrant will create a file named Vagrantfile in your current directory with a predefined configuration in it, and download and start the virtual machine.

It will also create a sub-directory named .vagrant (leading dot is not a mistake ๐Ÿ™‚ ). Those two we will use for our multi-project configuration with single virtual machine.

That’s it – you have just installed your Vagrant virtual machine successfully!

Now type:

$ vagrant ssh

And voila – you are in!

Now – exit from the machine by typing:

$ exit

or just press Ctrl-D simultaneously – that will end your Vagrant session and will bring you back in the console of your own computer. Now stop Vagrant:

$ vagrant halt

Basic Vagrant commands

The very basic Vagrant commands you must be familiar with are:

  • vagrant halt – stops the currently running machine
  • vagrant up – starts virtual machine (form the directory – checks for Vagrantfile)
  • vagrant ssh – login in Vagrant virtual machine

Vagrantfile

What is Vagrantfile

In order to work, Vagrant needs Vagrantfile present, so it will know how to start and configure your machine.

It checks directory hierarchy to try to find one – you can check the documentation here. But in our example we will presume that it always will be in the directory where your project is, and you will always start it from that particular directory.

Vagrantfile contains more or less the following:

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

# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
Vagrant.configure("2") do |config|
  # The most common configuration options are documented and commented below.
  # For a complete reference, please see the online documentation at
  # https://docs.vagrantup.com.

  # Every Vagrant development environment requires a box. You can search for
  # boxes at https://vagrantcloud.com/search.
  config.vm.box = "hashicorp/bionic64"

  # Disable automatic box update checking. If you disable this, then
  # boxes will only be checked for updates when the user runs
  # `vagrant box outdated`. This is not recommended.
  # config.vm.box_check_update = false

  # Create a forwarded port mapping which allows access to a specific port
  # within the machine from a port on the host machine. In the example below,
  # accessing "localhost:8080" will access port 80 on the guest machine.
  # NOTE: This will enable public access to the opened port
  # config.vm.network "forwarded_port", guest: 80, host: 8080

  # Create a forwarded port mapping which allows access to a specific port
  # within the machine from a port on the host machine and only allow access
  # via 127.0.0.1 to disable public access
  # config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"

  # Create a private network, which allows host-only access to the machine
  # using a specific IP.
  # config.vm.network "private_network", ip: "192.168.33.10"

  # Create a public network, which generally matched to bridged network.
  # Bridged networks make the machine appear as another physical device on
  # your network.

  # Share an additional folder to the guest VM. The first argument is
  # the path on the host to the actual folder. The second argument is
  # the path on the guest to mount the folder. And the optional third
  # argument is a set of non-required options.

  # Provider-specific configuration so you can fine-tune various
  # backing providers for Vagrant. These expose provider-specific options.
  # Example for VirtualBox:
  #
  # config.vm.provider "virtualbox" do |vb|
  #   # Display the VirtualBox GUI when booting the machine
  #   vb.gui = true
  #
  #   # Customize the amount of memory on the VM:
  #   vb.memory = "1024"
  # end
  #
  # View the documentation for the provider you are using for more
  # information on available options.

  # Enable provisioning with a shell script. Additional provisioners such as
  # Ansible, Chef, Docker, Puppet and Salt are also available. Please see the
  # documentation for more information about their specific syntax and use.
  # config.vm.provision "shell", inline: <<-SHELL
  #   apt-get update
  #   apt-get install -y apache2
  # SHELL
end

Again – there are many different options you could play with, but we will focus on ones that will give us the ability to use one virtual machine for more than one project.

Those options are:

  • config.vm.network – from here we will setup the network, so our virtual machine could be visible inside the local network (accessed from everywhere from within local network)
  • config.vm.synced_folder – with this we could attach different directories from our host computer (where Vagrant is running) to virtual machine

config.vm.network

That option will give us the ability to “see” our virtual machine from the local network. The options you should set in your Vagrantfile are:

config.vm.network "public_network", :use_dhcp_assigned_default_route => true

Which tells Vagrant to start the machine assigning the IP from the public network (our local network in this case) and ask the DHCP for the dynamic IP which it could use for the machine.

With this set, next time we run vagrant up, it will ask DHCP for dynamic IP from the network and will assign it to the virtual machine. If you are using Linux, after starting Vagrant, log into it and type:

$ifconfig

I know – ifconfig is deprecated and should not be used beacuse of IPv6 support bla-bla. I really doubt that your local network is using IPv6 ๐Ÿ™‚

You can easily install it by typing:

sudo apt install net-tools -y

But if you still think that this is bad idea – use this command instead:

ip -c a

That will give you pretty much the same results (check for eth1).

From here you should see the IP assigned to the machine:

eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.0.2.15  netmask 255.255.255.0  broadcast 10.0.2.255
        inet6 fe80::a00:27ff:febb:1475  prefixlen 64  scopeid 0x20
        ether 08:00:27:bb:14:75  txqueuelen 1000  (Ethernet)
        RX packets 905  bytes 113854 (113.8 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 683  bytes 115420 (115.4 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

eth1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.1.222  netmask 255.255.255.0  broadcast 192.168.1.255
        inet6 fe80::a00:27ff:fefe:60ec  prefixlen 64  scopeid 0x20
        ether 08:00:27:fe:60:ec  txqueuelen 1000  (Ethernet)
        RX packets 43  bytes 8244 (8.2 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 14  bytes 1236 (1.2 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 14  bytes 1188 (1.1 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 14  bytes 1188 (1.1 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

Here you can see the IP from the eth1inet 192.168.1.222, which means that you can access your machine on that IP – via browser, ping or whatever you prefer, from every computer located in the same network.

If you have more than one network adapter assigned to your computer, and Vagrant could not decide which one to use automatically it will show the following after vagrant up is executed:

==> default: Available bridged network interfaces:
1) en0: Wi-Fi (AirPort)
2) en1: Thunderbolt 1
3) en2: Thunderbolt 2
4) bridge0
5) p2p0
6) awdl0
7) llw0
==> default: When choosing an interface, it is usually the one that is
==> default: being used to connect to the internet.
==> default:
    default: Which interface should the network bridge to?

and will wait for you to select the proper one. Choose (like it suggests) the one connected to the internet – usually that is your WiFi adapter, in our example that is en0: Wi-Fi (AirPort), select 1 (in our case) and Vagrant will continue with booting the machine.

If you want you can put that in the Vagrantfile configuration, so from now on, when you are booting the machine it will not wait for your choice before continuing. To achieve that add the following to the config.vm.network:

config.vm.network "public_network", :use_dhcp_assigned_default_route => true, :bridge => "en0: Wi-Fi (AirPort)"

Where of course you should change the en0: Wi-Fi (AirPort), with your adapter’s name.

From now on the Vagrant will use that adapter and wont ask you to choose one.

config.vm.synced_folder

That option tells Vagrant to map folder from you computer (host) to your Vagrant machine. More details for that option you could see here.

In order to explain how to use that option we will presume the following:

You have the main projects directory, lets say it is MyProjects, located in your home directory. In that directory you have sub directory for every project, lets say it is MyFirstProject. In that folder you have cloned (GIT) the project (in sub directory), lets say it is my_first_project, so we have the following:

~/MyProjects/MyFirstProject/my_first_project/

Vagrant is initiated in ~/MyProjects/MyFirstProject and Vagrantfile and .vagrant directory are in that directory.

That project is a PHP project which needs to run from /var/www/html on your Vagrant machine.

So, given the above presumptions you need to map your host directory ~/MyProjects/MyFirstProject/my_first_project into /var/www/html on your Vagrant machine.

To achieve that you need to add the following to your Vagrantfile (located in ~/MyProjects/MyFirstProject):

  config.vm.synced_folder "./my_first_project", "/var/www/html",
    :owner => 'vagrant',
    :group => 'www-data',
    :mount_options => ['dmode=775', 'fmode=775']

with that you are telling the Vagrant to use my_first_project directory and map it to the /var/www/html on the virtual machine, set the owner to vagrant (that is the default vagrant user for Vagrant machine), set the group for those files to www-data (if you using default Apache config, otherwise – change that group respectively), and sets the permissions to 775.

That’s it – next time you boot the machine, you will have my_first_project in your Vagrant machine with the location /var/www/html

So your final Vagrantfile should look similar to:

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

# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
Vagrant.configure("2") do |config|
  # The most common configuration options are documented and commented below.
  # For a complete reference, please see the online documentation at
  # https://docs.vagrantup.com.

  # Every Vagrant development environment requires a box. You can search for
  # boxes at https://vagrantcloud.com/search.
  config.vm.box = "hashicorp/bionic64"

  # Disable automatic box update checking. If you disable this, then
  # boxes will only be checked for updates when the user runs
  # `vagrant box outdated`. This is not recommended.
  # config.vm.box_check_update = false

  # Create a forwarded port mapping which allows access to a specific port
  # within the machine from a port on the host machine. In the example below,
  # accessing "localhost:8080" will access port 80 on the guest machine.
  # NOTE: This will enable public access to the opened port
  # config.vm.network "forwarded_port", guest: 80, host: 8080
  # Create a forwarded port mapping which allows access to a specific port
  # within the machine from a port on the host machine and only allow access
  # via 127.0.0.1 to disable public access
  # config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"

  # Create a private network, which allows host-only access to the machine
  # using a specific IP.
  # config.vm.network "private_network", ip: "192.168.33.10"

  # Create a public network, which generally matched to bridged network.
  # Bridged networks make the machine appear as another physical device on
  # your network.
  config.vm.network "public_network", :use_dhcp_assigned_default_route => true, :bridge => "en0: Wi-Fi (AirPort)"

  # Share an additional folder to the guest VM. The first argument is
  # the path on the host to the actual folder. The second argument is
  # the path on the guest to mount the folder. And the optional third
  # argument is a set of non-required options.
  config.vm.synced_folder "./my_first_project", "/var/www/html",
    :owner => 'vagrant',
    :group => 'www-data',
    :mount_options => ['dmode=775', 'fmode=775']
  # Provider-specific configuration so you can fine-tune various
  # backing providers for Vagrant. These expose provider-specific options.
  # Example for VirtualBox:
  #
  # config.vm.provider "virtualbox" do |vb|
  #   # Display the VirtualBox GUI when booting the machine
  #   vb.gui = true
  #
  #   # Customize the amount of memory on the VM:
  #   vb.memory = "1024"
  # end
  #
  # View the documentation for the provider you are using for more
  # information on available options.

  # Enable provisioning with a shell script. Additional provisioners such as
  # Ansible, Chef, Docker, Puppet and Salt are also available. Please see the
  # documentation for more information about their specific syntax and use.
  # config.vm.provision "shell", inline: <<-SHELL
  #   apt-get update
  #   apt-get install -y apache2
  # SHELL
end

.vagrant directory

That directory is created when you init your Vagrant project. In that directory, Vagrant stores information about the machine, like name, ID, how to provision that machine etc.

That directory has the following structure:

.vagrant
โ”œโ”€โ”€ machines
โ”‚ย ย  โ””โ”€โ”€ default
โ”‚ย ย      โ””โ”€โ”€ virtualbox
โ”‚ย ย          โ”œโ”€โ”€ action_provision
โ”‚ย ย          โ”œโ”€โ”€ action_set_name
โ”‚ย ย          โ”œโ”€โ”€ box_meta
โ”‚ย ย          โ”œโ”€โ”€ creator_uid
โ”‚ย ย          โ”œโ”€โ”€ id
โ”‚ย ย          โ”œโ”€โ”€ index_uuid
โ”‚ย ย          โ”œโ”€โ”€ private_key
โ”‚ย ย          โ”œโ”€โ”€ synced_folders
โ”‚ย ย          โ””โ”€โ”€ vagrant_cwd
โ””โ”€โ”€ rgloader
    โ””โ”€โ”€ loader.rb

The information we are interested in is located in:

~/MyProjects/quotecites/.vagrant/machines/default/virtualbox

We will get back to it later, when explaining how to start another project using the same machine.

Set same Vagrant for another project

You already have your Vagrant setup and working. Lets see how we could use the same machine for another project (without the need to init, download and setup another one – which takes both – your precious time and resources (HDD).

We will follow the presumptions we made above. So your new project (we will call it MySecondProject) will go to the MyProjects dir. And the git project is cloned into my_second_project dir. Now we have the following structure:

MyProjects
โ”œโ”€โ”€ MyFirstProject
โ”‚ย ย  โ””โ”€โ”€ my_first_project
โ””โ”€โ”€ MySecondProject
    โ””โ”€โ”€ my_second_project

All you have to do is to copy Vagrantfile from ~/MyProjects/MyFirstProject to the ~/MyProjects/MySecondProject

And copy .vagrant (with all the content in it) dir as well – from ~/MyProjects/MyFirstProject/.vagrant to ~/MyProjects/MySecondProject/.vagrant

Now we have to change one thing in the VagrantFile, and that is the path to the mapped directory (synced folder) from this:

  config.vm.synced_folder "./my_first_project", "/var/www/html",
    :owner => 'vagrant',
    :group => 'www-data',
    :mount_options => ['dmode=775', 'fmode=775']

To that:

  config.vm.synced_folder "./my_second_project", "/var/www/html",
    :owner => 'vagrant',
    :group => 'www-data',
    :mount_options => ['dmode=775', 'fmode=775']

There is only one other step. We must delete 2 files, they are located inside .vagrant directory:

.vagrant
โ””โ”€โ”€ machines
 ย ย  โ””โ”€โ”€ default
 ย ย      โ””โ”€โ”€ virtualbox
 ย ย          โ”œโ”€โ”€ synced_folders
 ย ย          โ””โ”€โ”€ vagrant_cwd

Delete them (synced_folders and vagrant_cwd) and your setup is done.

Get back to ~/MyProjects/MySecondProject and run:

$ vagrant up

And voila – your Vagrant is now using your new configuration and you can start working on second project without the need to download and setup a new machine. It will use the same machine, every software and service installed and running on it, and the only difference will be the content of the /var/www/html directory – where your second project is now located.

If the machine is running already (on another project), then of course, you must stop / halt it before using it. For that reason my preferred set of commands for starting Vagrant are:

$ vagrant halt
$ vagrant up

With that you can be sure that there will be no collision with other instance of the same machine.

Single Vagrant for multiple projects – bonus

Lets say, that you have to work on multiple WordPress projects using Vagrant. That of course could be challenging if you work from lets say – home and office, and the DHCP assigns different IPs.

That could be a real pain in the ass, having to set the siteurl and home variables under WP. Or even worse if (God forbid) you need to work on the multiple sites under WP ๐Ÿ™‚ .

So lets make our lives easier by doing the following:

Open /etc/hosts (Windows users, please check with Google where it is on your OS) and add human readable domain to the IP assigned to your Vagrant like this:

(Linux like users (MacOS included)) make sure you are editing as admin when you are doing this:

Add anywhere on a separate line:

192.168.1.222 my-first-local-project.com

Where 192.168.1.222 is the IP of your Vagrant machine (you know how to get that from config.vm.network section of this article) and the my-first-local-project.com is the domain name which could be anything you like.

With that configuration in place you can access your Vagrant virtual machine by just using this domain. In case you are working on WP project – you could safely set that for siteurl and home. And next time you get a different IP address for some reason (switching networks for instance), just edit /etc/hosts and change the line with a new IP and restart Vagrant – that’s it.

(Stoil Dobreff)

See also:
Vagrant image for PHP developing


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *