For years I’ve eschewed using services such as HTML validators, because I was developing on my local machine, or even on a Virtual Machine inside my local machine; and external services couldn’t get to my website while it was under development. Worse yet, involving a webhook, a callback from a web based service, to your own website, was a chore because you had to deploy your site to a public-facing server before you could test it.
Until now. (Insert maniacal laugh here.)
I’ve recently started using a clever service called ngrok, which exposes your local development site to the Internet. Even if you’re behind a firewall.
(Quick aside. I believe it’s pronounced “en-grok”, rather than “n. g. rok”. Adherents of AngularJS will have to force themselves to conform.)
Yes, to be sure this is opening a big old hole in your security, but it’s a precise hole, for a given purpose. And it’s a controlled hole, because you can shut it down anytime you want. Plus, of course, you don’t have to advertise the new temporary URL.
Here’s How It Works
You download the ngrok application (and probably move it to /usr/local/bin
, or some other location on your path), and run it in a terminal window, with the following parameters:
ngrok http 80
This produces a dashboard display like so:
Now the Internet has a tunnel to your local webserver. When someone requests https://a69d3d5b.ngrok.io
, they’ll get your localhost content. Moreover, the requests will be shown on your dashboard.
If you need more detailed information about your requests and their responses, you can go to the Web Interface as shown on your dashboard. Just point your browser to https://127.0.0.1:4040
and you’ll be served this helpful fellow:
But wait! There’s more!
Virtual Hosts
What if your app isn’t located at localhost? What if you’ve got dozens of projects and each one has its own virtual domain, like https://raphael.dev
, where you’ve been playing with the SVG library? Not to worry, ngrok has you covered. Here’s your invocation:
ngrok http -host-header=rewrite raphael.dev:80
Now, as requests come in, ngrok rewrites the request to ask for raphael.dev.
Small Fly in the Ointment
I should probably mention one small fly in the ointment at this point. Every time you invoke ngrok, it’s going to generate a new, random alphanumeric subdomain name. For instance, the new one for the raphel.dev rewrite is https://a0a7c5c6.ngrok.io
. This isn’t a huge bother until you need to specify it to an external service, as we discussed at the beginning of this post, or shared it with a friend or customer. It’ll still work, of course; but each time you rerun ngrok, you’ll need to go change it on the external service, or share it again.
But ngrok has a solution for that, too. It’s going to cost a bit, but I think it’s well worth it. For $60 a year you get the ability to specify and reserve your own subdomain. For instance, I could reserve https://raphaeldev.ngrok.io
. Of course your invocation is going to change slightly:
ngrok http -subdomain=raphaeldev -host-header=rewrite raphael.dev:80
And for that same subscription fee I could reserve any number of subdomains.
So, when I specify my ngrok URL to an external service, it’s not going to be changing every time I want to reboot my machine. Brilliant!
In a Virtual Machine
Very good. We’ve got a tunnel to our local dev environment. But what if our dev environment is in a Virtual Machine, inside our local machine? No problem-o.
You’ve already setup your hosts
file in your host machine to point to the guest machine’s IP address, so you’re good to go. Invoke ngrok as usual from the host machine, and it will rewrite the ngrok.io
request to your mydomain.dev
; which will then be picked up by your hosts
file, and marshalled through to your VM.
All Set Then?
Well, not exactly. Now you’re getting to your page, but the page may have some issues. For instance, it may refer to assets such as JavaScript, CSS and images, with a fully qualified URL, including the domain name. So that’s a problem, because your user’s browser doesn’t know from mydomain.dev
. In such cases the best practice is to use relative addressing. Instead of https://mydomain.dev/css/style.css
, use /css/style.css
.
In fact, there are a couple of WordPress plugins (if you’re using WordPress) which do this for you: Relative URL, and Root Relative URL’s. The second one has over 50K installs, but hasn’t been updated in a couple of years, so I used the first one.
Any Other Issues?
Well, just one more, and it’ll bite you right in your WordPress back-end. The problem is when you want to reach your WP Admin page, there’s a redirect happening. But the redirect is to your mydomain.dev
, which gets pushed to your browser, and again, the browser doesn’t know squat about mydomain.dev
.
Happily, there’s a solution for this one as well. But first, let me mention that Alan Shreve, the outstanding developer who came up with ngrok, has been unflagging in his support, helping me get through every one of these hurdles. Also, when I described the redirection issue, he explained that the redirect response is passed on to the requesting client. But ngrok isn’t translating the response’s redirection URL. If it did, this would have worked at this point. So he’s planning on adding 301 and 302 rewriting to the app.
In the meantime, the solution is to rename your domain to mydomain.ngrok.io
. You’ll need to make a few changes to your setup. Here are the steps:
- Change your URL’s in wp-admin > General to
mydomain.ngrok.io
; - Add
mydomain.ngrok.io
in your host’s/etc/hosts
file (points to your VM’s IP); - Restart ngrok on your host machine, rewriting to the new URL;
- Modify
/etc/apache2/sites-available/25-av-....conf
: replace theServerName
withmydomain.ngrok.io
; - Restart Apache in your guest VM.
Of course, once you’v done that, you don’t need the relative URL plugins anymore. But it’s a journey.
And… You’re Done!
Be sure to test thoroughly.
Of course, in the case of webhooks, chances are you won’t run into redirects. But in case you do, this would cover you.
Now go forth and use external services with wild abandon!
This was so helpful. I’d been working on getting this going for hours. And your comments finally pulled it together. I am tunnelling wordpress multisite in circle ci to run ghost inspector tests. I gave up on relative urls and finally just converted the entire site, apache alias and all.
Glad it was useful to you, Deryk.