In praise of Cloudflare Tunnels for self-hosting
When self-hosting I’ll often setup a great application that works on my internal network but1,
- I want to access it when I’m not at home
- I don’t trust the application’s security and need an additional layer before exposing it to the internet
- I don’t want my application’s inbound traffic to go to my residential IP address
- I don’t want to pay $5/month for a box just to route traffic through
- I need to access these applications from computers I don’t fully control, for instances work computers
Some background on myself: I do self-hosting as a hobby, but I try to keep it as practical as possible, since I genuinely do need to use the applications I use, and I need them to be reliable and not too expensive. A couple years ago I switched from self-hosted Nextcloud to Dropbox because my Nextcloud box couldn’t handle generating thumbnails on all my photos: it wasn’t worth paying more than Dropbox for a custom solution that would struggle to let me scroll through thousands of photos.
This event also led me to avoid VPS’s. $6/month boxes are everywhere, and I still regularly use Vultr but with 1 vCPU tier any intensive tasks are not going to be fast enough to replace an SAAS solution. And, because most of this use is spiky, they need to be over-provisioned. Anything more complicated than a single shared CPU quickly breaks the inexpensive principle.
So, enter Patrick, my old gaming PC, following my cartoon-based naming scheme for my home network. I sold the GPU and now just use it as a server. This is useful even without any web applications: I’ll often SSH in and use yt-dlp to download some videos, run rtorrent to grab a Linux ISO, or have a long-running nethack4 game in tmux. I’ll also have some crons running, such as to back up Dropbox.
But, how do I run web applications? I’m a big fan of gitea but it’s not useful if I have to be home. Now, enter Cloudflare Tunnel. Create a system account, a systemd service, generate some credentials on Cloudflare’s web interface, and add a config,
tunnel: <Tunnel-UUID> credentials-file: /home/cloudflare-tunnel/.cloudflared/<Tunnel-UUID>.json ingress: - hostname: gitea.example.com service: http://localhost:8080 - service: http_status:404
And add the following CNAME entry:
It’s not so simple that it just works: there’s gaps in the documentation and you need to fiddle with settings to get an authentication layer in front. I still haven’t figured out how to remove that authentication layer: right now you need to give it an approved email to get to gitea, but that’s what I want anyway.
But it’s pretty close for this sort of thing. I can pretty much deploy a new self-hosted application on my home hardware in a few commands, a config change, and a DNS change from Cloudflare’s interface. I have a couple programs I wrote in python to scrape information from other sources and reformat them into less-distracting HTML files, and now I can just expose nginx as a private application and access those from anywhere.
This website isn’t hosted on Cloudflare since I have some misgivings on them throwing Captchas in front of anyone who looks suspicious, and exposing everyone who accesses my website to their traffic analysis. I’m not tyring to be a fanboy. But their team does some genuinely impressive things, and this is one of them. It’s a bit buggy in places, but it’s magical to me that I can re-use old hardware and have that routed for use over the internet, without exposing a residential IP address for free 2.
In the past I’ve tried to make posts here useful but I’ve started to write things that are just an opinionated stream of thoughts, and might as well post these instead of nothing. Expect some more. ↩︎
I did buy a power monitor at one point to measure how much I was paying to power that hardware and it’s about a few dollars a month. Even though running a desktop 24/7 is a significant chunk of power my marginal cost at current electricity usage is pretty low. I haven’t needed to upgrade my internet on behalf of self-hosting, since usage there is very low. ↩︎