Autostart ngrok with Rails
I’ve been using ngrok on quite a few projects lately. I’ve written about it before, but in short, it solves to problems for me.
- It tunnels back to localhost from a hostname that live on the net, allowing me to develop for webhooks that would barf on http://localhost:3000
- It provides a valid SSL cert. More and more the platforms I build apps for require HTTPS when talking to an app.
The downside is that it adds another moving part to the process. I’m too lazy for that, let’s automate it!
A little background, I recently upgraded to a paid ngrok
account, so
I could reserve subdomains. By default, ngrok
gives you a random
hostname, like, 23b0390b.ngrok.io, every time you run it, meaning you
have to reconfigure your webhooks whenever you restart it. With a paid
account, I can reserve a fixed hostname like, spikex.ngrok.io, problem
solved.
I had be using localtunnel which
has the advantage of being free, including use of (unreserved)
subdomains. However, I found it crashed randomly, and naturally during
client demos. I really appreciate the localtunnel
folks providing
this service, but I decided to paid ngrok
for something more stable.
Regardless of the tunnel, the point is that for a lot of my development work I need one and it’s one more window to open, one more process to start.
Fortunately, it turns out there’s a gem,
ngrok-tunnel, for
managing ngrok
. It goes in your Gemfile in the usual way, and I
stick it in my development/test block:
group :development, :test do
# [...]
gem 'ngrok-tunnel'
end
The gem provides command to stop, start, and get info about the tunnel:
Ngrok::Tunnel.start
=> "http://d5ccdf29.ngrok.io"
Ngrok::Tunnel.port
=> 3001
Ngrok::Tunnel.ngrok_url
=> "http://d5ccdf29.ngrok.io"
Ngrok::Tunnel.ngrok_url_https
=> "https://d5ccdf29.ngrok.io"
Ngrok::Tunnel.status
=> :running
Ngrok::Tunnel.stop
=> :stopped
Ngrok::Tunnel.status
=> :stopped
Note that the default port is 3001, where we typical run Rails on
3000, the :port
option controls this:
Ngrok::Tunnel.start(port: 3000)
=> "http://e5de1a61.ngrok.io"
Ngrok::Tunnel.port
=> 3000
With this, we can automate the process. Presuming you are using Rails
5 and Puma, stick the following at the end of config/puma.rb
:
if Rails.env.development?
require 'ngrok/tunnel'
options = { addr: ENV.fetch("PORT") { 3000 },
config: File.join(ENV['HOME'],'.ngrok2','ngrok.yml')
}
options[:subdomain] = ENV['NGROK_SUBDOMAIN'] if ENV['NGROK_SUBDOMAIN']
puts "[NGROK] tunneling at " + Ngrok::Tunnel.start(options)
end
(If you’re using something else this code will work in
config/unicorn.rb
, or config/thin.rb
as well.)
This will fire up ngrok
when Rails starts. If the environmental
variable NGROK_SUBDOMAIN is set, it will be use to set the ngrok
subdomain, otherwise a random one will be used. In either case, the
URL of the tunnel will be display.
If you are using localtunnel
, there’s a
gem for that too, so you can
easily apply the same logic using it.
There, laziness is satisfied, ngrok
starts and stops automatically
with the Rails server, one less thing to worry about.
Comments