home / blog / cloudflare tunnels ← zero open ports, zero worries

Cloud & Zero-Trust Networking

Cloudflare Zero-Trust Tunnels: Exposing Homelab Apps Without Port Forwarding

Published: August 2, 2026 • 13 min read · ← Back to Blog

Quick Reference Sheet

What it is for:
Safely exposing self-hosted apps, staging sites, and internal dashboards to the web without opening router ports or exposing your residential IP.
Who uses it:
Homelab Enthusiasts, Full-Stack Developers, Remote SysAdmins, and Security Engineers looking to bypass CGNAT.
Where it is useful:
Publishing portfolio demos, media portals, API backends, and internal dev tools behind automatic DDoS protection and email-based Zero Trust barriers.

Opening port 80 and 443 on your home router exposes your home IP address to automated bot scrapers, vulnerability scanners (like Shodan), and DDoS floods. Furthermore, many residential ISPs and cellular/satellite connections (Starlink) use CGNAT (Carrier-Grade NAT), making traditional port forwarding physically impossible because you do not have a dedicated public IPv4 address.

Cloudflare Tunnels solve this by establishing an encrypted, outbound-only connection from a lightweight daemon (cloudflared) running on your server directly to Cloudflare's global edge network. When visitors access your domain, Cloudflare proxies the traffic through this persistent tunnel directly to your local application container.

1. Installing the Cloudflare Tunnel Daemon (`cloudflared`)

On your Ubuntu/Debian server or Raspberry Pi node, install the official cloudflared binary:

# Download the official Cloudflare GPG key and repository package
curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | sudo tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null
echo "deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/cloudflared.list

# Update package cache and install cloudflared
sudo apt update && sudo apt install -y cloudflared

# Verify installation version
cloudflared --version

2. Authenticating & Creating a Named Tunnel

Authenticate the daemon with your Cloudflare account. This command generates a login URL in the terminal:

cloudflared tunnel login

Copy the output link into your browser, log in to your Cloudflare account, and select the zone/domain you want to attach the tunnel to. This automatically writes an authentication certificate to ~/.cloudflared/cert.pem.

Next, create a named tunnel for your infrastructure:

cloudflared tunnel create homelab-edge

This creates a tunnel ID (UUID) and saves a credentials JSON file in ~/.cloudflared/<TUNNEL-UUID>.json.

3. Building the Ingress Rules Configuration

Create the global configuration file for cloudflared:

sudo mkdir -p /etc/cloudflared
sudo nano /etc/cloudflared/config.yml

Define multi-service routing rules. Replace YOUR-TUNNEL-UUID with your actual tunnel UUID:

tunnel: YOUR-TUNNEL-UUID
credentials-file: /etc/cloudflared/YOUR-TUNNEL-UUID.json

ingress:
  # Route 1: Self-Hosted Streaming / Media Cloud (Example)
  - hostname: cvault.your-domain.com
    service: http://localhost:8096

  # Route 2: SmartStudy Collaborative App
  - hostname: smartstudy.your-domain.com
    service: http://localhost:3000

  # Route 3: Coolify PaaS Control Panel
  - hostname: coolify.your-domain.com
    service: http://localhost:8000

  # Mandatory Catch-All Rule (Drops unmapped requests)
  - service: http_status:404

Move the generated credentials file to the global /etc/cloudflared directory:

sudo cp ~/.cloudflared/YOUR-TUNNEL-UUID.json /etc/cloudflared/

4. Mapping DNS Routes to Your Tunnel

Create the CNAME DNS records pointing your subdomains directly to the tunnel endpoint:

cloudflared tunnel route dns homelab-edge cvault.your-domain.com
cloudflared tunnel route dns homelab-edge smartstudy.your-domain.com
cloudflared tunnel route dns homelab-edge coolify.your-domain.com

Cloudflare will automatically manage the CNAME records pointing to <TUNNEL-UUID>.cfargotunnel.com in your Cloudflare DNS dashboard.

5. Running as a Persistent System Service

Install cloudflared as a systemd service so it auto-starts whenever the server reboots:

# Point the service at YOUR config (default path would miss /etc/cloudflared)
sudo cloudflared --config /etc/cloudflared/config.yml service install
sudo systemctl enable cloudflared
sudo systemctl start cloudflared
sudo systemctl status cloudflared
Troubleshooting: 502 Bad Gateway / Connection Refused on Subdomains
Workaround: If visiting your subdomain returns a Cloudflare 502 error, check that the local service is actually listening on the exact port specified in config.yml (e.g. localhost:8096). If running inside Docker, ensure you bind the host port in Docker Compose (ports: - "8096:8096") or use the internal Docker container IP.

6. Adding Zero-Trust Access Barriers (Email OTP / GitHub OAuth)

For sensitive administrative portals (like Coolify or Proxmox), do not expose the raw login screen directly to the internet. Protect it with Cloudflare Zero Trust Access:

  1. Log in to the Cloudflare Zero Trust Dashboard (one.dash.cloudflare.com).
  2. Navigate to Access → Applications → Add an application → Self-hosted.
  3. Set Application Name (e.g. Coolify Admin Portal) and Subdomain (e.g. coolify.your-domain.com).
  4. Add an Access Policy: Set Action to Allow, and add Rule: Include → Emails (e.g. your-email@gmail.com).

Now, whenever anyone visits coolify.your-domain.com, Cloudflare intercepts the request and presents a sleek PIN verification prompt sent to your personal email address. Unauthenticated traffic is blocked at the edge before touching your server hardware.

Related Reads

“There is no cloud, just someone else's computer.”

— old hosting proverb