Jamie Lawrence

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 ``. 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 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


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
  - 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.


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