Cloudflare Tunnels for Local Development
Sometimes you need to open up your local dev machine to the internet to show some WIP or receive a webhook. Here’s a way to do that using Cloudflare Tunnels that works with subdomains, allows you to test Cloudflare headers, and doesn’t cost anything…
I will assume you have a domain on Cloudflare to create a permanent tunnel location. This is adapted from some notes I made at Podia and you can probably simplify some parts if you don’t need wildcard subdomain routing or have multiple people on your team.
Supporting subdomains locally
If you need to test subdomain locally, you can’t use `localhost` because `subdomain.localhost` doesn’t work. Instead, point an A record for a domain (e.g. *.local.ideasasylum.com) to `127.0.0.1`. Now you can browse to mysubdomain.local.ideasasylum.com and it’ll load from your local server.
I mention this because Cloudflare Tunnels are a great way to make that local server available on the Internet, including the subdomains which is often difficult to get working on tools like ngrok.
Install
Install the Cloudflare daemon:
brew install cloudflare/cloudflare/cloudflared
Login to Cloudflare:
cloudflared tunnel login
You must authorise against the domain you wish to use.
Create a tunnel using your first name:
cloudflared tunnel create $USER
The output will look like this:
Tunnel credentials written to /Users/jamie/.cloudflared/42fda061-312b-47c5-919d-22d0f45ad497.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 jamie with id 42fda061-312b-47c5-919d-22d0f45ad497
Note the tunnel id and location of the credentials for the next step
You can also list your tunnels: cloudflared tunnel list
Configure
Now create/edit a config file for your tunnel—usually in the app directory makes sense—called cloudflare_tunnel.yml
tunnel: '42fda061-312b-47c5-919d-22d0f45ad497'
credentials-file: /Users/jamie/.cloudflared/42fda061-312b-47c5-919d-22d0f45ad497.json
ingress:
- hostname: '*.jamie.tunnel.ideasasylum.com'
service: 'http://*.local.ideasasylum.com'
- service: 'http://*.local.ideasasylum.com'
Replace the tunnel id and credentials files with the values from earlier. This will tell the tunnel to accept traffic for *.jamie.tunnel.ideasasylum.com and send it to *.local.ideasasylum.com.
Create a route
Setup a route to for your tunnel which will create a CNAME DNS record for *.jamie.tunnel.ideasasylum.com
cloudflared tunnel route dns jamie "*.jamie.tunnel.ideasasylum.com"
This sets up a CNAME which will route traffic from *.jamie.tunnel.ideasasylum.com to our tunnel.
Start the tunnel
cloudflared tunnel --config cloudflare_tunnel.yml run
Start your local dev server.
Now going to mysubdomain.jamie.tunnel.ideasasylum.com will open your local dev environment to any one on the internet. These requests are routed through the Cloudflare network and will have Cloudflare headers.
Shutdown
To shutdown the tunnel, just kill the cloudflared app and requests can’t be routed to your local machine. To destroy your tunnel permanently, run
cloudflared tunnel delete jamie
Photo by Jakob Søby on Unsplash