Using ngrok to create a publicly accessible web-facing Raspberry Pi server
I have recently been tinkering around a lot with Arduinos and Raspberry Pis in my quest to build web-applications that interface with physical objects.
The Internet of Things is a topic that has gained a lot of popularity over the years, and, if many of the analyst predictions are right, will explode in popularity over the next 5 years. Many of the companies (e.g., SmartThings, Belkin WEMO, Nest, LIFX) that play in this space allow you to interact with physical objects around your house through the web.
I’ve built a number of different ways to connect physical objects to the web over the past few months as side projects. I’ve built apps that allow me to do the following through a web interface:
- Turn my lights on and off, change color based on time of day (supposed to be good for your Circadian rhythm), alert me when I get new tweets, etc.
- Turn on a motion detector that send me an email every time motion is detected in my room
- Control my coffee maker so that I have a steaming cup ready for me as soon as my alarm rings in the morning
- Announce the weather to me as I walk out the door in the morning (based on motion detected near my door)
However, I’ve built all of these in siloes and am now working on pulling it all together using a home automation hub that I’m building using a Raspberry Pi. The idea behind this hub is that it will run a Rails websocket (see my previous blog post on how I enabled this) that connects to an AngularJS front-end that I can access from anywhere in the world.
The advantage of using a Rapsberry Pi server running on my local home network is that all of the “smart” objects’ APIs, such as the LIFX API and the Sonos player API, only work if the messages are over the local network — you can’t just connect to someone else’s lights in someone else’s home (on a side note, here is a link to a hilarious app that a guy built that takes advantage of the fact that as long as you are on the network, you can control these “smart” objects).
However, to allow users to be able to send messages to these objects remotely, while not on my server, I had to make my Raspberry Pi server accessible from outside of my home network as well.
That’s where ngrok comes in.
ngrok is an AMAZING application that allows you to create “introspected tunnels to localhost”.
What does this mean? It means that it provides a publicly accessible IP address and domain name to your localhost server (in my case, I’m running a Rails server). You can just run a Rails app on your Rapsberry Pi (or your computer!) as you normally would using the rails -s command and then point ngrok to the port that you want to expose to the web.
This really takes away the headache of having to set up an Apache server on your Raspberry Pi and skirting your routers built in firewall (put in place to prevent users from accessing your network).
Here’s how you do it
For all of these steps, I’m assuming that you already have your Raspberry Pi set up with the operating system, installed Rails, SSH, and all the other initial steps (if you haven’t, this is a great tutorial).
- In the root of your local Rails repo, download the Linux/ARM version of ngrok and unzip it. This will be the executable file that you can use to run the ngrok tunnel later on once the app is on your Raspberry Pi
- Push your Rails code from your local development computer to Github
- SSH into your Raspberry Pi by typing in ssh pi@<your pi’s IP address> into your terminal
- Once you are SSHed into your Pi, pull down your Rails code from Github onto the local machine and bundle your gems (this can take a while since the Pi is far less powerful than a regular computer)
- Start your rails server using the rails -s command in your Pi SSH session
- In your Pi SSH session terminal, make sure you are in the top level of your application and type in ./ngrok 3000 . This tells ngrok to open up a web domain that routes everything that you have running on port 3000 and make it available on the domain that it specifies. You should see something like this:
Tunnel Status online
Forwarding http://6f73e7cf.ngrok.com -> 127.0.0.1:3000
Forwarding https://6f73e7cf.ngrok.com -> 127.0.0.1:3000
Web Interface 127.0.0.1:4040
# Conn 0
Avg Conn Time 0.00ms
This basically tells you that what you have on localhost:3000 is now running live, on the web at https://6f73e7cf.ngrok.com.
And voila, you your Raspberry Pi API can now take requests from anyone on the web!
Other things ngrok is good for
- Testing out live services, such as receiving emails at a specific domain
- Putting your web app up live for others to see while still in development (really fast deployment — don’t have to worry about the hassle of creating a staging environment if you’re looking to do this quickly).
- Setting up access for others to home servers or networks (e.g., if you want to provide someone with access to your music collection without using a service like Dropbox)