Emily T. Burak
Vagrant provisioning of Nginx on Ubuntu 14.04

Vagrant is a fantastic technology for experimenting with development virtual machine environments. For example, setting up a simple Nginx server, which was my introduction to Vagrant outside of using it for Linux VMs for learning.
Today I am going to focus on the technological context of the tools involved in Vagrant and Nginx, how to use them together to serve a simple site, some thoughts on my approach, and also ways to extend out this project and learning.
Some context -- what are Vagrant and Nginx?
Vagrant by HashiCorp(makers of the fantastic infrastructure provisioner Terraform and the secrets manager Vault, among other products) markets itself as "Development Environments Made Easy". Using a declarative syntax, Vagrant allows for reproducibility and portability of your development environment, reminding me of what Docker has done for containers, with its Vagrantfile being analogous to the Dockerfile in working to circumvent the "it works on my machine!" issue. Nginx is a robust web server option that is often used as a reverse proxy and/or load balancer in larger architectures, but here is used a simple server. Nginx is known to scale well, though that doesn't come into play in this relatively toy example, if one was building out something more serious it would definitely prove to be a benefit. Not knowing either well outside of some work with Nginx as a reverse proxy and with the Nginx Ingress Controller for Kubernetes, and some experimentation with virtual machines on Vagrant for practicing shell scripting, I decided on a simple use case inspired by this post on DevOps project ideas to learn the technologies better. I sought to do this using Vagrant to spin up a VM and run a static HTML page on an Nginx server running on the VM.
Using Vagrant and Nginx together for static HTML
To do so, I followed an incremental, iterative development process. Not knowing either technology well, I took it slow, starting with learning how to spin up a VM and work with a Vagrant file, then provisioning resources within that file through its shell provisioner, moving onto Nginx matters later like file setup and server configuration.
The important code is as follows, first is a Vagrantfile, written in Ruby (an early love and how I learned backend and OOP in the first place), but with a pretty clean syntax that was easy to set up. As well, the bulk of it is a shell script that adds a basic index.html and takes a simple-site configuration file copied from the source folder to set it up for serving by Nginx and serves it on port 81 on the localhost.
Vagrantfile:
# -*- mode: ruby -*- # vi: set ft=ruby : Vagrant.configure("2") do |config| config.vm.box = "ubuntu/trusty64" # 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" # Copy file from source directory to /tmp/ on VM. config.vm.provision "file", source: "./simple-site", destination: "/tmp/" # Provisioning with a shell script. config.vm.provision "shell", inline: <<-SHELL apt-get update apt-get install -y nginx # Adds /var/www/simple-site/html.index.html with Hello World mkdir -p /var/www/simple-site/html touch /var/www/simple-site/html/index.html echo '<h1>Hello World</h1>' >> /var/www/simple-site/html/index.html # Copies over the file provisioner provisioned simple-site file and makes it # available and enabed, restarts nginx to catch it with ufw open on port 81 cp /tmp/simple-site /etc/nginx/sites-available/ ufw allow 81 sudo ln -s /etc/nginx/sites-available/simple-site /etc/nginx/sites-enabled/ service nginx restart SHELL end
simple-site:
server { listen 81; # port on localhost; root "/var/www/simple-site/html"; # where to find the html file(s) index index.html; # the main file to serve up at landing point server_name _; # underscore to get around not having a domain location / { try_files $uri $uri/ =404; } }
Now, this works, displaying the appropriate text at port 81 of the provisioned virtual machine, something like this:

Lessons learned, improvements and extensions
However, there are definite flaws and places for improvement. For one, getting into a vagrant virtual machine through vagrant ssh gives fewer permissions than the root user that this shell script is run by default. Also, it looks like I could have used config.vm.synced_folder to not have to upload and copy the file or to do more interesting tricks. Finally, I will admit that I am still learning Nginx server blocks and all the options and syntax there, so it's likely a place for improvement as well in the simple-site file.
To extend out the project, I'm thinking of or at least would recommend anyone tinkering with VMs and Nginx to use a more dedicated configuration solution, such as Ansible, which integrates with Vagrant. You'd need to modify the port-based location of the server if you added a domain and wanted to serve up something potentially more complex, as well. In fact, most Nginx documentation I've seen presumes a domain, not localhost development, so there are resources out there for that task. For cloud deployment, Vagrant does have an AWS provider I may write something on later, but I've worked more with solutions like Terraform for similar tasks.
There are a lot of resources around Vagrant and Nginx, so it's awesome that you've chosen to read this one and give me some of your time. You are now released out into the world with this newfound knowledge. Get creating, provisioning, and configuring! Let me know in the comments or through social media if you have any thoughts or questions inspired by this blog post. The code for this project can be found here on GitHub.
Sources:
- https://devopscube.com/vagrant-tutorial-beginners/
- https://jgefroh.medium.com/a-guide-to-using-nginx-for-static-websites-d96a9d034940