# Self-Hosting at Home With Cloudflare Tunnel

> My Linux mini PC can run web apps, but CGNAT stops me from sharing them with a router port forward. Cloudflare Tunnel gives me a public URL while the app stays at home. Here's how it works, how it protects the server's IP, and where Cloudflare Access fits.

Published: 2026-10-17. Author: Milan Jovanović.

Canonical: https://milanjovanovic.tech/blog/cloudflare-tunnel-hide-backend-ip

[**Cloudflare Tunnel**](https://developers.cloudflare.com/tunnel/) lets you share a web app from home, even behind CGNAT.
Your server opens encrypted connections to Cloudflare, so you don't need your own public IP or router port forwarding.
The app stays on your server, and its URL is public unless you add access rules.

This is my [**Beelink SER9 MAX**](https://www.bee-link.com/products/beelink-ser9-max-amd-ryzen-7-h-255), 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.

<div className="grid grid-cols-2 gap-3">

![My Beelink SER9 MAX Linux mini PC resting in my hand.](https://milanjovanovic.tech/blogs/mnw_216/linux-mini-pc.webp)

![Adding RAM to my open Beelink mini PC, with one stick already in place.](https://milanjovanovic.tech/blogs/mnw_216/beelink-ram-install.webp)

</div>

## 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**](https://www.rfc-editor.org/rfc/rfc6269.html#section-5.2.1): 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**](https://developers.cloudflare.com/dns/manage-dns-records/how-to/managing-dynamic-ip-addresses/) 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`**](https://developers.cloudflare.com/tunnel/get-started/), 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**](https://developers.cloudflare.com/speed/troubleshooting/slow-website/#step-5-investigate-caching).
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.

![A Linux home server behind CGNAT opens an outbound tunnel. Cloudflare sends web requests through it without router port forwarding.](https://milanjovanovic.tech/blogs/mnw_216/cloudflare_tunnel_architecture.png)

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**](https://developers.cloudflare.com/cloudflare-one/faq/cloudflare-tunnels-faq/), 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.

![Requests to an open origin IP can skip Cloudflare and its rules.](https://milanjovanovic.tech/blogs/mnw_216/proxy_origin_bypass.png)

[**Old DNS records and other apps**](https://developers.cloudflare.com/fundamentals/security/protect-your-origin-server/) 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**](https://developers.cloudflare.com/ssl/faq/#why-do-i-see-a-cloudflare-certificate-when-an-ssl-certificate-is-installed-at-my-website), 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**](https://developers.cloudflare.com/tunnel/troubleshooting/https-origins/).

![Cloudflare reads HTTPS traffic and can check Access rules. The app still checks what each user may do.](https://milanjovanovic.tech/blogs/mnw_216/tunnel_security_boundaries.png)

The public URL is still open to visitors.
For my own admin page, I'd add [**Cloudflare Access**](https://developers.cloudflare.com/cloudflare-one/access-controls/applications/http-apps/self-hosted-public-app/) 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**](https://milanjovanovic.tech/blog/authentication-authorization-clean-architecture).
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**](https://developers.cloudflare.com/tunnel/concepts/routing/) 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**](https://www.wireguard.com/quickstart/) VPN to [**Traefik**](https://doc.traefik.io/traefik/reference/routing-configuration/tcp/tls/) 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**](https://milanjovanovic.tech/blog/build-your-own-vpn-with-tailscale) 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!

---

## Frequently asked questions

### Can I self-host behind CGNAT without port forwarding?

Yes. The cloudflared program connects from your home network to Cloudflare. Web requests return through those connections, so you do not need a router port forward. Your app still runs at home.

### Does Cloudflare Tunnel hide my server IP?

Your domain points to Cloudflare. Old DNS records or other apps can still leak your IP. Block direct web access too. A tunnel does not close open ports for you.

### How can an outbound tunnel serve web requests?

The cloudflared program opens encrypted connections from your server to Cloudflare. Requests and replies flow both ways. It passes requests to your app and sends the replies back through Cloudflare.

### Does Cloudflare Tunnel make my API private?

No. Anyone can reach the public URL. Use Cloudflare Access or your own login checks to control who can use the app.

### Is all the traffic encrypted?

HTTPS ends at Cloudflare, which can read the web traffic. The tunnel to your server is a separate encrypted link. The last step to your app uses HTTP or HTTPS, based on your setup.
