Creating Virtual Machines With Vagrant

Creating virtual machines can be a complex process. Why not automate it?

Vagrant is a command line utility for creating virtual machines quickly. In this tutorial you will create a Linux virtual machine running Apache and configure it to serve web pages in the current folder.

You can complete this tutorial on Windows or macOS. You will need VirtualBox installed and a fast Internet connection.

Installing Vagrant

Installing Vagrant is as easy as installing any other program. Visit https://www.vagrantup.com/ and download the installer for your operating system. Run the installer and accept any defaults presented.

Once Vagrant has finished its installation process, open a new command line interface and type

$ vagrant

to ensure that it works. You’ll see something like this:

Usage: vagrant [options] <command> [<args>]

    -v, --version                    Print the version and exit.
    -h, --help                       Print this help.

Common commands:
...
     up              starts and provisions the vagrant environment
     version         prints current and latest Vagrant version

For help on any individual command run `vagrant COMMAND -h`

Additional subcommands are available, but are either more advanced
or not commonly used. To see all subcommands, run the command
`vagrant list-commands`.

Vagrant is ready to go. Now you can configure your first virtual machine.

Creating A Machine

We’re going to create a basic Ubuntu machine using a “base box.” This is a preconfigured virtual machine ready for use with Vagrant. This machine already has the OS installed for you. So instead of downloading an ISO that you have to manually install when you the machine, you just download a ready-made machine that “just works.”

First, open a command prompt or terminal and create a folder to work in:

$ mkdir vagrant
$ cd vagrant

Then execute this command:

$ vagrant init hashicorp/precise64

This creates a new file called Vagrantfile which defines the virtual machine’s settings. It configured it to use a base box for Ubuntu 12.04 LTS provided by Hashicorp, the creators of Vagrant.

Next, run

$ vagrant up

When you first run this command, it will check to see if the base box is on your computer. And since this is the first time you’ve tried this, it won’t be found, so it’ll download it:

Bringing machine 'default' up with 'virtualbox' provider...
==> default: Box 'hashicorp/precise64' could not be found. Attempting to find and install...
    default: Box Provider: virtualbox
    default: Box Version: >= 0
==> default: Loading metadata for box 'hashicorp/precise64'
    default: URL: https://atlas.hashicorp.com/hashicorp/precise64
==> default: Adding box 'hashicorp/precise64' (v1.1.0) for provider: virtualbox
    default: Downloading: https://atlas.hashicorp.com/hashicorp/boxes/precise64/versions/1.1.0/providers/virtualbox.box
    default: Progress: 74% (Rate: 6371k/s, Estimated time remaining: 0:00:13)

Next, it configures the machine:

==> default: Successfully added box 'hashicorp/precise64' (v1.1.0) for 'virtualbox'!
==> default: Importing base box 'hashicorp/precise64'...
==> default: Matching MAC address for NAT networking...
==> default: Checking if box 'hashicorp/precise64' is up to date...
==> default: Setting the name of the VM: apache_default_1456513889780_29262
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
==> default: Forwarding ports...
    default: 22 (guest) => 2222 (host) (adapter 1)

Once it’s configured, it boots and connects to the machine over SSH with a user called vagrant that it sets up:

==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:2222
    default: SSH username: vagrant
    default: SSH auth method: private key
    default:

Vagrant uses public and private key pairs for logging in instead of passwords, and it needs to generate new keys whenever we create a new machine. The default key is just there to get things started. But it’s not secure since everyone has a copy of the default key when Vagrant is installed. Think of this like a password reset from “12345” to something really complex.

    default: Vagrant insecure key detected. Vagrant will automatically replace
    default: this with a newly generated keypair for better security.
    default:
    default: Inserting generated public key within guest...
    default: Removing insecure key from the guest if it's present...
    default: Key inserted! Disconnecting and reconnecting using new SSH key...
==> default: Machine booted and ready!

Next, it verifies if guest additions are configured right. In some cases you may see this message:

==> default: Checking for guest additions in VM...
    default: The guest additions on this VM do not match the installed version of
    default: VirtualBox! In most cases this is fine, but in rare cases it can
    default: prevent things such as shared folders from working properly. If you see
    default: shared folder errors, please make sure the guest additions within the
    default: virtual machine match the version of VirtualBox you have installed on
    default: your host and reload your VM.
    default:
    default: Guest Additions Version: 4.2.0
    default: VirtualBox Version: 4.3

For what we’re doing, you can ignore this message and move on.

The last thing Vagrant does is configure a shared folder. Any file we create in the current working folder will be available in a folder called /vagrant within the virtual machine:

==> default: Mounting shared folders...
    default: /vagrant => /Users/brianhogan/tmp/apache

At this point, the virtual machine is running.

Type the command

$ vagrant ssh

to log in.

Welcome to Ubuntu 12.04 LTS (GNU/Linux 3.2.0-23-generic x86_64)

 * Documentation:  https://help.ubuntu.com/
New release '14.04.4 LTS' available.
Run 'do-release-upgrade' to upgrade to it.

Welcome to your Vagrant-built virtual machine.
Last login: Fri Feb 26 19:18:43 2016 from 10.0.2.2
vagrant@precise64:~$

Find the machine’s IP address with ifconfig:

`ifconfig eth0 | grep 'inet addr`
If you wanted just the IP address, you can use the `cut` and `awk` commands to get that: ```shell_session $ ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{print $1}' ```

Now type exit to exit out of the machine.

Now, destroy this machine. We’re going to build it again.

$ vagrant destroy

You’ll be asked if you want to destroy the machine. Enter y:

    default: Are you sure you want to destroy the 'default' VM? [y/N] y
==> default: Forcing shutdown of VM...
==> default: Destroying VM and associated drives...

And that’s it. Now let’s do something more interesting.

Creating A Web Server Machine

We’re going to use Vagrant to quickly set up Ubuntu and the Apache web server to serve HTML files from the current folder. That means we need an HTML file.

In the current folder, create the file index.html using your favorite text editor. Inside of this file, create an h1 tag with your name in it. Here’s an example file:

<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <title>Brian's site</title>
    <link rel="stylesheet" href="stylesheets/style.css">
  </head>
  <body>
    <h1>Brian Hogan</h1>
  </body>
</html>

Next, edit the Vagrantfile. We’re going to uncomment several sections within the file.

Setting the Name

By default, Vagrant calls your machine default. And that’s not good if you want to have multiple virtual machines managed by Vagrant. So naming your machine will help keep things clear.

We actually have two names to change. First we want to change the name that Vagrant uses to reference the machine. And then we want to change the name that VirtualBox uses to create the machine.

First, locate this section:

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

Right below that section, add this line to define the name of the Vagrant machine:

  config.vm.define "bhogan_apache"

But use your CVTC Username, not mine.

Next, locate this section:

  # 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

This is the section that configures the VirtualBox virtual machine. It’s commented out, so VirtualBox will use default settings. The comments here explain the options. By default, the vb.gui option is turned off. This way VirtualBox will not pop up and open when you start a machine, which is great for servers.

Remove the hash marks from the first and last lines of this section, and delete the other lines. Make sure it looks like this:

  config.vm.provider "virtualbox" do |vb|

  end

Then, in between these lines, add this line to give your machine a name. This is the name that will display in VirtualBox’s user interface.

  vb.name = "bhogan_apache"

Again, use your CVTC Username, not mine.

The section should now look like this:

  config.vm.provider "virtualbox" do |vb|
		vb.name = "bhogan_apache"
  end

But with your own username, of course.

Configure Networking

Our machine will run the Apache web server, but in order to access it, we’ll have to do some port forwarding. Apache runs on port 80. And so we’ll configure Vagrant to forward traffic from our computer to this virtual machine. When we access localhost:8080 in our web browser, the request will go to our virtual machine and be served by Apache!

Locate this line:

  # config.vm.network "forwarded_port", guest: 80, host: 8080

and remove the hash mark in front of the line to uncomment it. Piece of cake! All requests to our local machine’s port 8080 get routed to the virtual machine’s port 80.

Sharing files

We want to serve any files in our current folder with Apache running in the virtual machine. Vagrant makes this easy to do. Locate this part of the configuration file:

  # 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 "../data", "/vagrant_data"

Below that, add a line of configuration that maps the current folder (.) to /var/www, the folder Apache uses to serve web pages.

  config.vm.synced_folder ".", "/var/www"

And that’s it. All the files in this folder will be synchronized to the /var/www folder within the virtual machine!

Automatically Install Apps

When we create our machine, we want to update the OS to install any security fixes, and we want to install Apache. Find this section:

  # config.vm.provision "shell", inline: <<-SHELL
  #   sudo apt-get update
  #   sudo apt-get install -y apache2
  # SHELL

When a machine is “provisioned”, or built from scratch, this section runs. And by default, it has almost exactly what we need. So remove the comments from this section so it looks like this:

  config.vm.provision "shell", inline: <<-SHELL
    sudo apt-get update
    sudo apt-get install -y apache2
  SHELL

Save the configuration file and return to your command prompt or terminal.

Creating the machine

Just like last time, run the vagrant up command to create the machine.

$ vagrant up

This time, you won’t have to download the base box, because it’s already there. It will see if the base box needs an update though:

Bringing machine 'default' up with 'virtualbox' provider...
==> bhogan_apache: Importing base box 'hashicorp/precise64'...
==> bhogan_apache: Matching MAC address for NAT networking...
==> bhogan_apache: Checking if box 'hashicorp/precise64' is up to date...
==> bhogan_apache: Setting the name of the VM: bhogan_apache

Then it configures your network:

==> bhogan_apache: Clearing any previously set network interfaces...
==> bhogan_apache: Preparing network interfaces based on configuration...
    bhogan_apache: Adapter 1: nat
==> bhogan_apache: Forwarding ports...
    bhogan_apache: 80 (guest) => 8080 (host) (adapter 1)
    bhogan_apache: 22 (guest) => 2222 (host) (adapter 1)

It then boots the machine and replaces the key:

==> bhogan_apache: Booting VM...
==> bhogan_apache: Waiting for machine to boot. This may take a few minutes...
    bhogan_apache: SSH address: 127.0.0.1:2222
    bhogan_apache: SSH username: vagrant
    bhogan_apache: SSH auth method: private key
    bhogan_apache:
    bhogan_apache: Vagrant insecure key detected. Vagrant will automatically replace
    bhogan_apache: this with a newly generated keypair for better security.
    bhogan_apache:
    bhogan_apache: Inserting generated public key within guest...
    bhogan_apache: Removing insecure key from the guest if it's present...
    bhogan_apache: Key inserted! Disconnecting and reconnecting using new SSH key...
==> bhogan_apache: Machine booted and ready!

After checking the guest additions, it attempts to create the shared folders you told it to create:

==> bhogan_apache: Mounting shared folders...
==> bhogan_apache: Mounting shared folders...
    bhogan_apache: /var/www => /Users/brianhogan/tmp/apache

Finally, it runs the provisioning script we asked it to run.

==> bhogan_apache: Running provisioner: shell...
    bhogan_apache: Running: inline script
==> bhogan_apache: stdin: is not a tty
==> bhogan_apache: Ign http://us.archive.ubuntu.com precise InRelease
==> bhogan_apache: Get:1 http://us.archive.ubuntu.com precise-updates InRelease [55.7 kB]
==> bhogan_apache: Get:2 http://security.ubuntu.com precise-security InRelease [55.7 kB]
...
==> bhogan_apache: Fetched 6,312 kB in 5s (1,100 kB/s)

And then installs Apache!

==> bhogan_apache: Reading package lists...
==> bhogan_apache: Reading package lists...
==> bhogan_apache: Building dependency tree...
==> bhogan_apache:
==> bhogan_apache: Reading state information...
==> bhogan_apache: The following extra packages will be installed:
==> bhogan_apache:   apache2-mpm-worker apache2-utils apache2.2-bin apache2.2-common libapr1
==> bhogan_apache:   libaprutil1 libaprutil1-dbd-sqlite3 libaprutil1-ldap ssl-cert
==> bhogan_apache: Suggested packages:
==> bhogan_apache:   www-browser apache2-doc apache2-suexec apache2-suexec-custom
==> bhogan_apache:   openssl-blacklist
==> bhogan_apache: The following NEW packages will be installed:
==> bhogan_apache:   apache2 apache2-mpm-worker apache2-utils apache2.2-bin apache2.2-common
==> bhogan_apache:   libapr1 libaprutil1 libaprutil1-dbd-sqlite3 libaprutil1-ldap ssl-cert
==> bhogan_apache: 0 upgraded, 10 newly installed, 0 to remove and 185 not upgraded.
==> bhogan_apache: Need to get 1,859 kB of archives.
==> bhogan_apache: After this operation, 5,697 kB of additional disk space will be used.
==> bhogan_apache: Get:1 http://us.archive.ubuntu.com/ubuntu/ precise/main libapr1 amd64 1.4.6-1 [89.6 kB]
...
==> bhogan_apache: Setting up apache2-mpm-worker (2.2.22-1ubuntu1.10) ...
==> bhogan_apache:  * Starting web server apache2
==> bhogan_apache: apache2: Could not reliably determine the server's fully qualified domain name, using 127.0.1.1 for ServerName
==> bhogan_apache:    ...done.
==> bhogan_apache: Setting up apache2 (2.2.22-1ubuntu1.10) ...
==> bhogan_apache: Setting up ssl-cert (1.0.28ubuntu0.1) ...
==> bhogan_apache: Processing triggers for libc-bin ...
==> bhogan_apache: ldconfig deferred processing now taking place

And if you visit http://localhost:8080 in your browser, you’ll see the web page you created earlier!

Log into the machine

Use

$ vagrant ssh

to log into the machine. Then use the cat command to verify the contents of the file /var/www/index.html to make sure it’s yours:

$ cat /var/www/index.html

And sure enough, you see the file you created.

Type

$ exit

to exit the virtual machine.

Then type

$ vagrant halt

to gracefully shut down this virtual machine. You can start it again with

vagrant up

whenever you need it.

Using Vagrant Machines Directly Through VirtualBox

Behind the scenes, Vagrant is just making VirtualBox do the things you’d normally set up yourself, but in a faster way.

Open VirtualBox and you’ll find your machine listed in the sidebar. Start it up like normal and you’ll be able to run it as if you’d installed it yourself. Log in with the username vagrant and the password vagrant.

Vagrant machine running in VirtualBox

To shut the machine down, either send the shutdown signal, or go back to your terminal and issue the

$ vagrant halt

command again. Vagrant will tell VirtualBox what to do.

Wrapping Up

In this tutorial, you learned how to create Linux virtual machines with Vagrant. You can use this to create development environments to test your code, or quickly prepare production machines. By default, Vagrant uses VirtualBox, but you can use different providers to use Vagrant to create machines on Amazon’s EC2 offerings or on other cloud providers.

In addition, you can use Vagrant to set up Windows virtual machines.

Exercises

First, ensure you have a working Apache webserver configured exactly as stated in this tutorial.

Then, create a Widnows virtual machine with Vagrant, with the following settings:

  1. Initialize a new Vagrant project in a new folder. Create the folder, and then inside that folder, create the Vagrantfile.
  2. Use modernIE/w7-ie11 as the base box.
  3. Name the machine yourname_windows7 where youranme is your CVTC username. Remember to do this in both the main configuration and the provider configuration.
  4. Ensure the virtual machine has 1024 GB of Ram when you create it.
  5. Ensure that the GUI for VirtualBox is enabled.
  6. Delete all other commented lines in the configuration file so only the active configuration remains.