Cloudflare Tunnels for Homelab Access

Accessing your home lab from the outside used to mean open ports, dynamic DNS, and hoping your firewall rules held.

Cloudflare Tunnels change the game. No inbound ports. No exposed services. Just secure outbound connections.

How It Works

Instead of opening port 443 on your router, cloudflared runs on your server and establishes an outbound connection to Cloudflare’s edge network.

┌──────────┐     ┌─────────────────┐     ┌─────────────┐     ┌──────────────┐
│ Internet │────▶│ Cloudflare Edge │◀────│ cloudflared │────▶│ Your Service │
└──────────┘     └─────────────────┘     └─────────────┘     └──────────────┘

                                    (outbound connection)

Traffic flows:

  1. User requests app.yourdomain.com
  2. Cloudflare receives the request at their edge
  3. Cloudflare routes it through the tunnel to your server
  4. Your server responds back through the same tunnel

Your firewall stays locked. No inbound rules needed.

Zero Trust Authentication

The tunnel alone isn’t the killer feature. Zero Trust Access is.

Every request gets authenticated before reaching your service:

  1. Identity check - Valid Google/GitHub/Okta login required
  2. Email domain - Only @yourdomain.com allowed
  3. Device posture (optional) - Require managed devices
  4. Geographic restrictions (optional) - Block specific countries
# Access policy example
- name: "Admin Access"
  decision: allow
  include:
    - email_domain: yourdomain.com
  require:
    - login_method: google

Even if someone finds your tunnel URL, they can’t access it without authenticating through your identity provider.

Setting Up the Tunnel

Install cloudflared

# Debian/Ubuntu
curl -L --output cloudflared.deb https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
dpkg -i cloudflared.deb

# Or via Docker
docker run cloudflare/cloudflared:latest tunnel --no-autoupdate

Authenticate

cloudflared tunnel login

Opens a browser to authenticate with your Cloudflare account.

Create the Tunnel

cloudflared tunnel create homelab

This generates a credentials file. Keep it safe.

Configure Routes

Create ~/.cloudflared/config.yml:

tunnel: homelab
credentials-file: /root/.cloudflared/<tunnel-id>.json

ingress:
  - hostname: code.yourdomain.com
    service: http://localhost:8080
  - hostname: grafana.yourdomain.com
    service: http://localhost:3000
  - hostname: requests.yourdomain.com
    service: http://localhost:5055
  - service: http_status:404

Each hostname routes to a different internal service.

Run as a Service

cloudflared service install
systemctl enable cloudflared
systemctl start cloudflared

The tunnel starts on boot and reconnects automatically.

Services I Expose

VS Code Server

Full IDE in the browser. Edit code from anywhere.

- hostname: code.yourdomain.com
  service: http://localhost:8443

Protected by Zero Trust — requires authentication before you see the login page.

Monitoring Dashboard

Grafana dashboards showing server health, build status, network metrics.

- hostname: monitor.yourdomain.com
  service: http://localhost:3000

Media Requests (Overseerr)

This one allows public access but with Cloudflare WAF rate limiting:

- hostname: requests.yourdomain.com
  service: http://localhost:5055

No Zero Trust here — it’s meant for family/friends to request media.

Split-Horizon DNS

When I’m home, I don’t want traffic going through Cloudflare. It should stay local.

External (via Cloudflare):

  • code.yourdomain.com → Cloudflare Tunnel → localhost:8443

Internal (local DNS):

  • code.yourdomain.com → 192.168.1.100:8443

My local DNS (Pi-hole/AdGuard) returns local IPs for these domains. When I’m away, public DNS returns the Cloudflare proxy.

Security Benefits

Port ForwardingCloudflare Tunnel
Expose ports to internetNo inbound ports
DDoS hits your connectionDDoS stopped at Cloudflare edge
Manual firewall rulesZero Trust policies
SSL certificate managementAutomatic SSL via Cloudflare
Your IP exposedYour IP hidden behind Cloudflare

Limitations

  • Latency - Traffic goes through Cloudflare. Adds a few ms.
  • Bandwidth - Free tier has limits on certain features
  • Dependency - If Cloudflare is down, so is your access
  • Not for all traffic - Gaming, streaming, high-bandwidth might suffer

For admin tools, dashboards, and remote access, the tradeoff is worth it.

Debugging

# Check tunnel status
cloudflared tunnel info homelab

# Run in foreground for debugging
cloudflared tunnel run homelab

# Test locally
curl -I https://code.yourdomain.com

Zero inbound ports. Identity-aware access. Remote admin from anywhere. This is how homelabs should connect to the internet.