Simple, Modern LEMP Using Vagrant

Vagrant is an indispensable part of my development tool belt for quickly spinning up a local environment on Mac OS X. When used with VirtualBox, it provides cheap, easy, disposable servers that alleviate any fears of breaking something or catastrophic loss.

At it's heart Vagrant is simple to configure and run, but can become increasingly overwhelming as your needs grow more and more complex. While provisioning tools such as Chef, Puppet, SaltStack, and Ansible help with complexity, they aren't necessary for, and at times hinder, "quick and easy" setups. We will ignore them here.

Let's create a simple, modern LEMP stack utilizing the following components:

  • Ubuntu 14.04
  • Nginx 1.8.x
  • MySQL 5.7
  • PHP7

We will build the server via the command line in order to remove any cruft between ourselves and the machine, facilitating a more innate understanding of the process.

Note: These instructions are purposefully limited in scope to support ease of use, ignoring most configuration, security, and best-practices commonly utilized on a production server. This is fast and loose.

Vagrant and Ubuntu 14.04

Let's begin by installing Vagrant onto the machine we are working from. Visit the downloads page and perform the installation.

Additionally, Vagrant uses a provider which performs the actual virtualization of the environment. Two common providers are VirtualBox and VMWare. We will use VirtualBox for the reason that it is free. Visit this page, download the software, and perform the installation.

With Vagrant and VirtualBox successfully installed it's time to move forward. Let's create a directory to hold the required files. Open your console of choice and run the following commands:

$ cd ~/Documents
$ mkdir MyVagrant && cd MyVagrant
$ mkdir html

Note: The final command above creates a MyVagrant/html directory which will be used later. You can ignore it for the moment.

Now, with a few more simple commands, we can immediately build and start a virtual Ubuntu 14.04 machine.

Note: You will be downloading a base box for the first time, which may take a while to complete. Boxes only need to be downloaded once, and can then be reused on many virtual machines.

$ vagrant init ubuntu/trusty64
$ vagrant up

Once vagrant up is executed, your virtual machine is using space and resources on your computer. At any time you can remove the virtual machine by running vagrant destroy and free up the used space and resources. Need the machine back? Simply run vagrant up again.

Note: For a full list of vagrant commands, visit this page.

At this point, you can execute vagrant ssh and you will be automatically SSH'd into the virtual machine. Go ahead and explore. Once you are done looking aound, simply logout.

As noted in the console, vagrant init created a Vagrantfile. This file holds the instructions used to build the base environment. Using your text editor of choice, take a moment to investigate the Vagrantfile and it's configuration options.

Note: You can create as many Vagrantfiles as you want, provided they are in different locations, but be aware that any vagrant ... commands must be executed in the directory containing the Vagrantfile you want to reference. In our case, since we are in the MyVagrant directory, the vagrant ... commands are using that Vagrantfile.

Let's make and implement a few changes to our current Vagrantfile. Using your text editor, find the following line:

# config.vm.network "private_network", ip: "192.168.33.10"

And uncomment it:

config.vm.network "private_network", ip: "192.168.33.10"  

Then find the line:

# config.vm.synced_folder "../data", "/vagrant_data"

Uncomment and edit it to read:

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

Note: Both edits to the Vagrantfile above will come in to play shortly when we introduce Nginx, but recognize that the first argument of config.vm.synced_folder is in reference to the html directory we created earlier.

With those changes made, save the modified Vagrantfile and execute vagrant reload on the command-line. This will implement our edits and restart the virtual machine.

Nginx 1.8.x

With our virtual machine up and running, let's install our first component, Nginx. Begin by logging in to the machine using vagrant ssh.

Let's use the most recent stable version of Nginx and since the default Ubuntu repository has a slightly out-of-date version, we need to start by adding an additional repository. To do so, execute the following commands:

$ sudo add-apt-repository -y ppa:nginx/stable
$ sudo apt-get update

Once those commands have completed successfully, we can install Nginx.

$ sudo apt-get install -y nginx

After the installation is complete, we should have a fully functioning web server. Test this out by visiting http://192.168.33.10/. You should see the default Nginx welcome page. Additionally, if you look in the MyVagrant/html directory, you should see a new file called index.nginx-debian.html.

But where did that URL come from? And the HTML file?

The URL was set when we edited config.vm.network in our Vagrantfile. We set private_network to an ip address of 192.168.33.10.

The second edit we made was to config.vm.synced_folder and we synced html to /var/www/html. The first argument is the folder on our local machine relative to the Vagrantfile and the second argument is the folder on our virtual machine. The syncing gives us access to our virtual machine through our local filesystem. In our case, /var/www/html is the default web root for Nginx and we can get access to those files via the local html folder.

If you closed it, re-visit http://192.168.33.10/. Now open up MyVagrant/html/index.nginx-debian.html and make a change. Modify some text, change a style, anything you'd like. Save your edits and then refresh that page in your browser. You should see your changes immediately reflected! As you can see, synced folders are a powerful feature of Vagrant.

We won't get any deeper into Nginx, but you can explore it's configuration on your own.

MySQL 5.7

Most websites need a data store. MySQL is an immensely popular option, and one that is quite easy to install. If you aren't still, log back in to the virtual machine using vagrant ssh.

Again, the Ubuntu repositories hold an older version of MySQL. As such, we need to take a few extra steps to get access to MySQL 5.7. Run the following commands first:

$ wget http://dev.mysql.com/get/mysql-apt-config_0.3.5-1ubuntu14.04_all.deb
$ sudo dpkg -i mysql-apt-config_0.3.5-1ubuntu14.04_all.deb

You will be prompted to set some configuration options. On the initial screen select Server and hit return. Then arrow down to select mysql-5.7-dmr and hit return. Then, again, arrow down to Apply and hit return. You will then be returned to the command-line. Continue with:

$ rm mysql-apt-config_0.3.5-1ubuntu14.04_all.deb
$ sudo apt-get update
$ sudo apt-get install -y mysql-server-5.7

You will be prompted to input and confirm a password for the root user. Once installation is complete, you can access MySQL with mysql -u root -p. You will be asked for the password which you just created and once you are authenticated, you can interact with MySQL using it's command-line interface.

PHP7

Finally, let's install PHP7, the newest version. It's fast. Almost twice as fast as the previous version, 5.6 (mileage may vary of course). Once again, let's add a repository in order to get version 7.0 and install the package.

$ sudo add-apt-repository -y ppa:ondrej/php
$ sudo apt-get update
$ sudo apt-get install -y php7.0-fpm php7.0-cli

Depending on your application and use-case, you may need to add some PHP extensions. For instance, since we just installed MySQL, let's install that extension.

$ sudo apt-get install -y php7.0-mysql

Not all extensions have been upgraded for PHP7, although the majority of them have. If you are in doubt, check this resource.

We also need to make a few changes to the Nginx configuration in order to a) serve .php files, and b) use PHP7. On the virtual machine edit the file /etc/nginx/sites-available/default. For instance, run sudo nano /etc/nginx/sites-available/default. We need to edit the following lines to add index.php. Change:

# Add index.php to the list if you are using PHP
index index.html index.htm index.nginx-debian.html;  

to:

# Add index.php to the list if you are using PHP
index index.php index.html index.htm index.nginx-debian.html;  

We also need to uncomment and edit a few lines of a location block. Look for:

# location ~ \.php$ {
#     include snippets/fastcgi-php.conf;
#
#     # With php5-cgi alone:
#     fastcgi_pass 127.0.0.1:9000;
#     # With php5-fpm:
#     fastcgi_pass unix:/var/run/php5-fpm.sock
# }

And change it to:

location ~ \.php$ {  
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
}

Exit and save the changes, then restart Nginx.

$ sudo service nginx restart

If you visit http://192.168.33.10/ again, you should see no change, but it should still work. Let's create a simple .php file to test PHP. in our MyVagrant/html directory, create a file index.php and add this line:

<?php phpinfo(); ?>  

Save the file, and revisit http://192.168.33.10/. You should now be greeted with the the default PHP info page.

Conclusion

Throughout this tutorial we have managed to install Vagrant and VirtualBox and spin up a quick Ubuntu 14.04 virtual machine. Then we were able to install the following components:

  • Nginx 1.8.x
  • MySQL 5.7
  • PHP7

With a few small configuration changes we successfully served a PHP page and edited files in our web-server root via the synced MyVagrant/html folder on our local filesystem.

Photo by Paul Itkin at Unsplash