Allowing Access to Vagrant Instances from the Internet

Allowing Access to Vagrant Instances from the Internet

aka: “how do I use Vagrant with ngrok”

I’ve been working with a client whose developers use both Vagrant and ngrok very heavily. Here is what the developers like about both of them:

Vagrant:

  1. provides ability to spin up/down local development instances very quickly and consistently.
  2. the vagrant instances also run configuration management (in this case, Puppet) ensuring that the configuration is production-like

Ngrok:

  1. tunnels ports from the public internet (typically ports 80 and 443) to a given port on your own host, allowing connectivity to development instances from other hosts and devices. An example would be connecting an iOS or Android device to a vagrant instance.

Problem: accessibility, efficiency and consistency

  1. The developers were running into problems connecting hosts (typically iPhones and Android devices) to their local vagrant development instances
  2. Although easy to use, ngrok configuration was performed manually and usage wasn’t consistent developer to developer

Solution: vagrant with foodshow plugin

I solved both of these problems using a the vagrant plugin vagrant-foodshow – this vagrant plugin modifies vagrant port forwarding so that the host port also becomes the destination port of an ngrok tunnel. As all of the developers share one vagrant file, this also had the benefit of automating ngrok configuration and ensuring consistency of ngrok use. A screenshot of the results are below:

vagrant-foodshow-ngrok - Running in Chrome
Connectivity to a vagrant virtual machine from the public internet.
vagrant-foodshow-ngrok - Bootup
vagrant bootup with foodshow plugin configured.

 

Solution: the code

The Vagrantfile used to accomplish this below, and has also been checked into my snippets GitHub repository at https://github.com/colinbjohnson/snippets:

vagrantfile_api_version = "2"
if Vagrant.has_plugin?('vagrant-foodshow')
 ngrok_enabled = true
else
 ngrok_enabled = false
end
Vagrant.configure(vagrantfile_api_version) do |config|
config.vm.network "private_network", ip: "192.168.2.2"

if ngrok_enabled == true
 print "Ngrok enabled.\n"
 config.foodshow.enabled = true
 # using config.foodshow.subdomain will host your vagrant instance at the
 # given subdomain - for instance, you could host at my_subdomain.ngrok.com
 # instead of 94f3bdd.ngrok.com
 # config.foodshow.subdomain = 'my_subdomain'
 # config.foodshow.authtoken is required if using config.foodshow.subdomain
 # add your authtoken below
 # config.foodshow.authtoken = 'my_authtoken'
 config.vm.network :forwarded_port, guest: 80, host: 8080, ngrok_proto: "http+https"
 else
 $stderr.print "Ngrok not enabled.\n"
 end
config.vm.box = "ubuntu/precise64"
end

Two final notes:

  1. The above configuration exposes your vagrant instance to the public instance. If this is a concern, ngrok supports authentication to protect the destination service.
  2. My hope is to find time to create a private network shared amongst only the host OS, guest OS and the additional host, if it is an iOS or Android device.