Imagine you want to test a new page that you just wrote the code for against a real mobile device. You don’t want to push it into production without testing it. You somehow need to expose your local Rails server to the internet so that you (or anyone else) could test it before it goes live.
These is a very common problem. Luckily, it’s been solved already. My go-to tool for this was ngrok or localtunnel. Both of these tools are great, but they didn’t fit my needs perfectly.
Ngrok is very advanced, but I don’t need all of its features. The feature that I need is a static domain name, so that I can expose my local Rails app to the same address. On the free version, ngrok binds to a subdomain assigned to you randomly. A static domain name is a must if you want to save time developing your app.
Localtunnel is an open-source alternative to ngrok that allows you to do just that:
There are a bunch of problems with localtunnel, though:
It’s not maintained anymore, although it still works
Downtimes do happen
Sometimes, the tunnel just crashes, or your subdomain doesn’t get bound
To address the former, I wrapped my localtunnel in a while loop like this:
while true; do lt –port 3000 –subdomain=telebugs –print-requests; sleep 1; done
Anyone can hijack the subdomain that you use when your tunnel is not active.
In fact, this happened to me last year, so I had to choose another subdomain:
Welp, crypto bros have “hijacked” my localtunnel subdomain that I’ve been using for Synonym Sprint.
I had to choose a new name instead.
It happened yesterday, and I thought maybe today it would be free again, but no, it is still running.
It’s not a big deal, since changing is… pic.twitter.com/G9eL8Lq4Hq
— Kyrylo Silin (@kyrylosilin) December 29, 2023
Meet the Cloudflare Tunnel
Your domain name must be managed by Cloudflare. Otherwise, this tutorial will not work for you.
Why would you go through all these struggles, when around the corner, there’s a better alternative that solves all our problems?
Without further ado, let’s replace ngrok/localtunnel with
Cloudflare Tunnel in our Rails 7 app!
Installation
Let’s install the cloudflared CLI app. On macOS, it’s as simple as:
Confirm that it’s installed via:
cloudflared version 2024.3.0 (built 2024-03-19T18:08:31Z)
Create a new tunnel
First, you need to log into your Cloudflare account via cloudflared so that
you can manage CF tunnels via the CLI:
A browser window should have opened at the following URL:
https://dash.cloudflare.com/argotunnel?aud=&callback=https%3A%2F%2Flogin.cloudflareaccess.org%2F0n1R7UqQdRd7vR3D4CT3D4wzHoB0-63_RZ63vSVzIhakw%3D
If the browser failed to open, please visit the URL above directly in your browser.
You have successfully logged in.
If you wish to copy your credentials to a server, they have been saved to:
/Users/kyrylo/.cloudflared/cert.pem
Choose the domain for your Rails app and click “Authorize”. That’s all!
Now, you need to create a named tunnel. I will name my tunnel telebugs:
Tunnel credentials written to /Users/kyrylo/.cloudflared/3de42678-313b-4801-bd71-1e4dda81880b.json. cloudflared chose this file based on where your origin certificate was found. Keep this file secret. To revoke these credentials, delete the tunnel.
Created tunnel telebugs with id 3de42678-313b-4801-bd71-1e4dda81880b
You will use that tunnel to access your local Rails app. Now you need to update your DNS records to point to that tunnel. Choose a subdomain that you would like to use to access your local Rails app. localhost seems like a good choice: it’s easy to understand, and it’s unlikely you will want it for your production needs.
2024-03-31T09:59:33Z INF Added CNAME localhost.telebugs.com which will route to this tunnel tunnelID=3de42678-313b-4801-bd71-1e4dda81880b
Configure your Rails app to use the tunnel
Create config/cloudflare-tunnel.yml with the following contents:
tunnel: 3de42678-313b-4801-bd71-1e4dda81880b
credentials-file: /Users/kyrylo/.cloudflared/3de42678-313b-4801-bd71-1e4dda81880b.json
ingress:
– hostname: localhost.telebugs.com
service: http://localhost:3000
– service: http_status:404
Note: you must use the full path for credentials-file. Cloudflare will not
expand $HOME or ~/ for you, so
~/.cloudflared/3de42678-313b-4801-bd71-1e4dda81880b.json will fail:
Next, validate the tunnel’s ingress:
Validating rules from config/cloudflare-tunnel.yml
OK
Ok, we’re all good. Now we can add this file to .gitignore, copy its contents
to config/cloudflare-tunnel.yml.example, redact tunnel and
credentials-file values, and track it with git:
tunnel: CHANGE_ME
credentials-file: CHANGE_ME
ingress:
– hostname: localhost.telebugs.com
service: http://localhost:3000
– service: http_status:404
One last thing we need to do is add localhost.telebugs.com to the list of allowed domains so that Rack doesn’t block it:
Rails.application.configure do
config.hosts << “localhost.telebugs.com”
end
Run the tunnel
Awesome! We can now start using our tunnel. Let’s confirm that it works:
2024-03-31T11:19:10Z INF Starting tunnel tunnelID=3de42678-313b-4801-bd71-1e4dda81880b
Now, make sure your local Rails app is running, navigate to
https://localhost.telebugs.com (use your own domain), and verify that your local Rails server gets hit.
HTTP/2 200
Nice! We’re almost done!
Starting the tunnel every time is a hassle, so add it to the Procfile, so that
it is started automatically every time you launch your Rails app locally.
Edit Procfile and add the following:
tunnel: cloudflared tunnel –url localhost:3000 –config config/cloudflared-tunnel.yml run telebugs
Now, every time you run bin/dev, your Rails 7 application will start the tunnel, and you will be able to access your local server from anywhere on the internet. For free!
Was the article helpful? Follow me on X/Twitter
where I post daily about my indie hacking journey and the projects I work on.