📧 Self-Hosting at Home With Cloudflare Tunnel
Self-Hosting at Home With Cloudflare Tunnel
Read on: my website / Read time: 5 minutes
The .NET Weekly is brought to you by:
Token caps and cheaper models shrink your AI bill by shrinking what you get from it, and they do nothing about the growing dataset sitting in expensive RAM. Redis tackles both at the source, with semantic caching so you stop paying to generate the same answer twice and Redis Flex so only hot data stays in RAM. See how to cut AI costs without cutting AI.
and by:
Developer Toolkit for the AI Era
Datadog's free Developer Toolkit for the AI Era gives developers four resources to close the visibility gaps that slow AI delivery, from CI pipeline visibility and flaky test detection all the way to LLM observability and safe AI feature rollouts
You'll learn how to:
- Detect flaky tests and surface CI pipeline failures before they block your AI delivery cycles.
- Instrument LLM calls to catch quality, latency, and cost regressions before they reach production.
- Use feature flags and DORA metrics to roll out AI features safely and measure delivery confidence.
This is my Beelink SER9 MAX, a mini PC I use as a Linux home server. I bought it barebones, so it came without RAM or SSDs.
I added 16 GB RAM and two 256 GB SSDs. Both refurbished. The whole build cost me about $500. I'm pretty happy with this, considering the current memory prices.
Why Port Forwarding Won't Work for Me
At home, I can reach an app using the server's local IP. However, a friend on another network can't use that address.
Normally, I could forward a port on my router to the app. But I'm behind CGNAT: my ISP shares a public IPv4 address across several homes. There's another address-sharing layer at the ISP, and I don't control it.
A port forward on my router only handles my side. It doesn't make that shared public IP send requests to my home.
I also don't have a static IP. Dynamic DNS can keep a name pointed at a changing IP, but it can't get through CGNAT on its own.
A tunnel lets my server connect out, then carry web requests back in. That gives me a way to share an app without asking my ISP for a public IP.
My Server Opens the Connection
I'd run cloudflared, Cloudflare's open-source tunnel connector, on my Linux server. It runs in the background, either as a service or in Docker.
Its job is to open encrypted connections to Cloudflare and keep them open. Outbound means my server starts those connections. Requests and replies can still flow both ways.
I'd map api.example.com to http://api:8080 on my Docker network. When a web request needs my app, Cloudflare sends it through the tunnel. cloudflared passes it to the app, then sends the app's reply back through Cloudflare.
That extra hop can add latency, though cached files may load faster. I'd measure from where my users are.
Visitors use a normal browser, with no need to install cloudflared. My API's port can stay private.
My router can block new inbound web connections. If my home IP changes, the tunnel can reconnect. The domain still points to Cloudflare.
I could use this to share a small web app or receive a webhook from a service. The app still runs on my mini PC.
Tunnel is free, though a domain and power still cost money. If my home connection or power goes down, visitors can't reach the app. I've got a UPS, so that adds some redundancy.
This isn't so important since I'm not running anything mission critical. But keep this in mind if you want to give self-hosting on your own infra a try.
Why Hiding an IP Isn't Enough
If you have a public server, you may already use Cloudflare as a reverse proxy. It forwards web requests to your backend, or origin, while your domain points to Cloudflare's IPs.
But your server may still accept direct requests. Someone who knows its IP can skip Cloudflare and its rules by sending the right hostname.
Old DNS records and other apps can leak the IP. I'd want my server to block direct web access even if someone finds it.
Tunnel gives Cloudflare a way to reach the app with those public ports closed. I'd still need to close the old web routes myself. I'd test IPv4 and IPv6 from outside, and keep a private way to log in.
It won't hide the IP used by other traffic from my server.
Who Can Read the Traffic?
HTTPS ends at Cloudflare, so Cloudflare can read the web traffic. The tunnel is encrypted too, but it's a separate link. I'd need to trust Cloudflare with that data.
The last step, from cloudflared to http://api:8080, uses plain HTTP. If that crosses a network I don't trust, I'd use HTTPS and check its certificate.
The public URL is still open to visitors. For my own admin page, I'd add Cloudflare Access to let only approved users reach the tunnel. I'd also set cloudflared or the app to check the Access token.
A public API can keep its own login system. The app still needs rules for what each user can do. Being signed in shouldn't let you read someone else's data.
What I'd Choose
I'd start with what I want to protect, and from whom. That's my threat model.
For my home lab, the main benefit is being able to share an app at all. Tunnel gives me a public URL without a port forward or a static IP.
Cloudflare's DDoS protection and Access may also help if you have a public IP. Small sites can be targets too.
But a tunnel alone can't stop a flood of requests sent to a known home IP from filling the internet link.
If I don't want Cloudflare to read the traffic, I could rent a VPS. It could pass TCP port 443 through a WireGuard VPN to Traefik at home.
With TLS passthrough, HTTPS stays intact until it reaches Traefik. If I end HTTPS on the VPS instead, it can read the traffic.
I'd keep my home IP out of public DNS, but the VPS host could still see it. This also means a server bill, patches, possible bandwidth fees, and checking its DDoS limits.
If your setup already meets your needs, there's no need to replace it.
For just my own devices, I'd use a private Tailscale network instead.
I'm releasing Pragmatic Self-Hosting next week. If you've been thinking about running your own apps, I'll share the details when it launches.
Thanks for reading.
And stay awesome!
27 links in this issue
- my websiteeefd4225.click.convertkit-mail4.com
- Rediseefd4225.click.convertkit-mail4.com
- Developer Toolkit for the AI Eraeefd4225.click.convertkit-mail4.com
- Beelink SER9 MAXeefd4225.click.convertkit-mail4.com
- CGNATeefd4225.click.convertkit-mail4.com
- Dynamic DNSeefd4225.click.convertkit-mail4.com
- cloudflaredeefd4225.click.convertkit-mail4.com
- cached files may load fastereefd4225.click.convertkit-mail4.com
- Tunnel is freeeefd4225.click.convertkit-mail4.com
- Old DNS records and other appseefd4225.click.convertkit-mail4.com
- HTTPS ends at Cloudflareeefd4225.click.convertkit-mail4.com
- HTTPS and check its certificateeefd4225.click.convertkit-mail4.com
- Cloudflare Accesseefd4225.click.convertkit-mail4.com
- rules for what each user can doeefd4225.click.convertkit-mail4.com
- DDoS protectioneefd4225.click.convertkit-mail4.com
- WireGuardeefd4225.click.convertkit-mail4.com
- Traefikeefd4225.click.convertkit-mail4.com
- private Tailscale networkeefd4225.click.convertkit-mail4.com
- Xeefd4225.click.convertkit-mail4.com
- LinkedIneefd4225.click.convertkit-mail4.com
- YouTubeeefd4225.click.convertkit-mail4.com
- Katabencheefd4225.click.convertkit-mail4.com
- .NET Architects Clubeefd4225.click.convertkit-mail4.com
- Patreoneefd4225.click.convertkit-mail4.com
- Join 5,000+ software engineerseefd4225.click.convertkit-mail4.com
- Join 2,800+ software engineerseefd4225.click.convertkit-mail4.com
- Join 1,900+ software engineerseefd4225.click.convertkit-mail4.com
Sent by The .NET Weekly. Links that track readers or name the subscriber were removed from this copy; its images still load from the sender's own servers. If you publish this newsletter and want an issue corrected or removed, write to us.


