Cloudflare Tunnels
Every now and then I need to expose a service running on a local machine to the internet, usually just temporarily. Rather than opening ports on a router or mucking about with firewall rules, a reverse tunnel does the job nicely.
There are a number of providers offering this kind of reverse tunnel, including:[1]
I've been playing around with Cloudflare Tunnel recently. Its client, cloudflared, supports a couple of different modes: anonymous quick tunnels (transient, randomly-named URLs) and named tunnels, which are tied to a Cloudflare account and give you stable, predictable hostnames.
Quick tunnels
If you just want to throw something onto a public URL for an hour, TryCloudflare needs no account and nothing more than the cloudflared binary. For example, to share a local web server listening on port 8080:
cloudflared tunnel --url http://localhost:8080cloudflared connects out to Cloudflare's edge and prints a randomly generated URL:
https://some-random-words-here.trycloudflare.comAnyone with that URL can now reach your local server through Cloudflare's network.
A few caveats worth knowing before you rely on these:
- The tunnel and its URL live only as long as the
cloudflaredprocess runs. HitCtrl-Cand it's gone, and you'll get a fresh random URL next time you start one. - They're intended for testing and development only.
Named tunnels
For anything longer-lived, named tunnels give you a stable hostname of your choosing. These require a Cloudflare login, and a domain served by Cloudflare DNS.
First, authenticate and create the tunnel:
# Opens a browser window to authenticate
cloudflared tunnel login
# Creates the tunnel and a credentials file (~/.cloudflared/<UUID>.json)
cloudflared tunnel create my-tunnel
# Confirm it exists
cloudflared tunnel listNext, create a configuration file at ~/.cloudflared/config.yml mapping hostnames to local services:
tunnel: <UUID>
credentials-file: /home/you/.cloudflared/<UUID>.json
ingress:
# Map a public hostname to a local service
- hostname: app.my-site.com
service: http://127.0.0.1:8080
# Required catch-all rule; anything unmatched gets a 404
- service: http_status:404Ingress rules are evaluated from top to bottom, and the last rule must be a catch-all. Services can be more than plain HTTP: SSH, RDP, arbitrary TCP, Unix sockets and more are supported. Other top-level options (like protocol and edge-ip-version) can tune how cloudflared connects to the edge.
Then route a DNS record to the tunnel and start it up:
# Creates a CNAME for app.my-site.com
cloudflared tunnel route dns my-tunnel app.my-site.com
# Start serving traffic
cloudflared tunnel run my-tunnelA couple of additional commands that are useful for debugging:
# Sanity-check the ingress rules in your config
cloudflared tunnel ingress validate
# Check which rule a given URL would match
cloudflared tunnel ingress rule https://app.my-site.com
# See connection status for a running tunnel
cloudflared tunnel info my-tunnelAll in all, these commands provide a quick and convenient way to expose tools and services from your local machine to the internet. Especially if you already use Cloudflare as your site's DNS. Given this blog is hosted on Cloudflare Pages, this was the obvious choice for me to try first. It ended up doing everything I needed it to - so I didn't end up trying any of the other entries in the list. ↩