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

I have been running several different websites or web services for like 15-20 years now. Usually, I use dedicated servers for things that have to be reachable from the internet since I didn’t have a local server or didn’t want to punch a hole into my router and expose myself to the internet. This changed over the past 2-3 years. I wanted to have network storage for media files, some space for RAW photos and a server that runs my home automation.

Since my local setup runs on an Unraid server, failing HDD are not that much of an issue anymore since I can just replace the broken HDD and Unraid will rebuild the storage pool without data loss. But you don’t have to work in IT for decades to know that a RAID is not a backup. So I set up off-site backup for important data as well. Things I have never really done on my remote servers beside some randomly created database dumps.

So, now I have a local server with backups that runs perfectly fine for my local services. Spooling up a new Docker container and making it available to my local network is quick and easy thanks to Traefik and my local DNS. Since everything’s working so well, I wanted to use my local server for services that should be available on the internet as well. To make them available I would have to open up port 80 and/or 443 in my router OR make them only available while being connected to my Tailscale VPN. Open 80/443 on the router? Nope. Access services only while being connected via VPN? Yes, but no. Two of the services I wanted to have externally available are Miniflux for RSS, Atuin for shell history syncing and linkding for bookmarks.

Tailscale is not just a simple VPN. They also provide several extras like MagicDNS and Tailscale Funnel. MagicDNS will make all nodes within a “Tailnet” available via a domain. You basically choose your Tailnet name and there you go. Your nodes will now be available via <node name>.<tailnet name>.ts.net. Here’s already one downside. I can make different services (distinguished by their ports) available on different subdomains while running on the same server. More about that in my post about my local DNS. This wouldn’t work with only the node being via its own domain. Another downside: I am locked to the ts.net domain, since Tailscale does not yet allow custom domains for MagicDNS. The lack of custom domains is something that I cannot work around right now. The problem with “only full nodes are available via MagicDNS” is something that I can actually work around.

A few months ago, Tailscale introduced tsnet. Basically some sort of library, that can be built into your application, to connect your application directly with your Tailnet. With that knowledge, someone built a tool called tsdocker which allows you to connect any Docker container directly with Tailscale and make it available as a node in your Tailnet. Since I am running an Unraid server, I use the UI for most things. Managing some containers manually via the CLI would be annoying. A few weeks ago, a blog post on the Tailscale community/dev blog has been published announcing a “docker mod” which can be easily attached to any linuxserver.io Docker image via environment variables.

This solution would work perfectly fine if it wouldn’t lock me down to linuxserver.io’s images. I would have to re-create many of the images I use which then forces me to update them manually as well. So again, this is not really a solution that suits me well right now. So, I needed a different solution. I found out that Cloudflare provides something that does exactly what I wanted called Cloudflare Tunnel. Since this post started to become quite long already, I chose to split them apart. I will talk about Cloudflare Tunnel in part 2.