Expose local services to the internet with Tailscale or Cloudflare (part 2)

Since part 1 became quite long I thought splitting the post in two would make it easier to simply link it to people who are interested in either the Tailscale or the Cloudflare way. As mentioned in part 1, part 2 will explain how I expose my local hosts to the internet via Cloudflare Tunnel.

In general, I didn’t want to open up port 80 and 443 on my home router and forward these ports to my server to then handle the rest. I already want to expose some services to the internet which are hosted on my local server which is scary enough. No need to tell everyone that here’s something interesting to find.

In comes Cloudflare Tunnel. It basically does similar things like Tailscale Funnel. I have a secure channel between me and Cloudflare’s servers without me having to open any kind of ports. Cloudflare allows me to use my own domains to expose local services and they handle the proxying through their servers including wildcard TLS certificates.

Things are absurdly easy to setup. For the local part, I simply have to set up cloudflared. Luckily, they provide a docker image for that which only requires a tunnel token, which I’ll explain after the snippet.

docker run
  -d
  --name=cloudflare-tunnel
  --net=host
  -e TUNNEL_TOKEN=xxx
  cloudflare/cloudflared:latest tunnel --no-autoupdate run local

This will start up all I need. Everything the container sees can be tunneled. To lock it down a little further, a dedicated docker network can be used.

In order to make this work, cloudflared requires some setup on the Cloudflare Zero Trust Dashboard. A tunnel has to be created. Right after creating it, the site presents the value I need for TUNNEL_TOKEN. I am using a single tunnel for multiple services. Once created, I can add public hostnames

I can choose one of my existing domains, enter a subdomain and for the service, I simply point it to the local accessible IP/hostname + port. As mentioned, I can point it to everything that is accessible to the container.

cloudflare dashboard

That’s literally it. Since I am using Cloudflare’s DNS for upstream DNS requests, this subdomain is immediately available.