Cloudflare Zero Trust for Homelab Remote Access
Cloudflare Zero Trust gives your homelab secure remote access without exposing any ports on your router. No port forwarding, no dynamic DNS headaches, no firewall ACLs to maintain. Your services stay behind your NAT; Cloudflare acts as the secure gateway.
Photo by Andrey Matveev on Unsplash
It sounds too good to be true, but the mechanics are legitimate. A lightweight cloudflared daemon running on your homelab creates an outbound encrypted tunnel to Cloudflare's edge. When someone accesses your domain, Cloudflare routes the traffic through that tunnel. Your home IP is never exposed.
The free tier handles everything most homelab users need.
The Basic Architecture
User → Cloudflare Edge → cloudflared tunnel → Your homelab services
Inbound ports: none needed. All connections are initiated outbound by cloudflared. This is why it works behind carrier-grade NAT, ISPs that block ports 80/443, and networks you don't control (hotel, office, mobile).
The additional piece — Zero Trust Access — layers identity verification on top. Before Cloudflare routes traffic to your homelab, it checks who the user is. This is separate from (and in addition to) any auth your services have themselves.
Setting Up Cloudflare Tunnel
Prerequisites
- A domain managed by Cloudflare (or transfer one — Cloudflare offers competitive registrar pricing)
- A Cloudflare account (free tier works)
- Docker on your homelab host
Step 1: Create a Tunnel
In the Cloudflare dashboard:
- Navigate to Zero Trust → Networks → Tunnels
- Click Create a tunnel
- Name it (e.g.,
homelab-tunnel) - Cloudflare generates a tunnel token — save this
Step 2: Run cloudflared
# docker-compose.yml
version: '3'
services:
cloudflared:
image: cloudflare/cloudflared:latest
container_name: cloudflared
restart: unless-stopped
command: tunnel run
environment:
- TUNNEL_TOKEN=your_tunnel_token_here
network_mode: host
docker-compose up -d
The tunnel connects immediately. You'll see it show as "Healthy" in the Cloudflare dashboard.
Step 3: Add Public Hostnames
In the tunnel configuration, add routes:
| Subdomain | Service |
|---|---|
proxmox.yourdomain.com |
https://localhost:8006 |
grafana.yourdomain.com |
http://localhost:3000 |
nas.yourdomain.com |
http://localhost:5000 |
Cloudflare creates DNS CNAME records automatically. Within minutes, proxmox.yourdomain.com resolves through Cloudflare's network and routes to your Proxmox UI.
Adding Zero Trust Access Policies
A tunnel alone makes your services reachable — but reachable by anyone. Zero Trust Access adds authentication: only approved identities can get through.
Configuring an Access Application
- Go to Zero Trust → Access → Applications
- Click Add an application → Self-hosted
- Fill in:
- Application name: Proxmox
- Subdomain:
proxmox.yourdomain.com
- Add a policy:
- Policy name: Personal access
- Action: Allow
- Rule: Emails — enter
[email protected]
When someone tries to access proxmox.yourdomain.com, Cloudflare intercepts and shows a login page. After authenticating (Google, GitHub, email OTP, or your choice), they're let through. The request then goes through the tunnel to Proxmox.
Identity Providers
Cloudflare Zero Trust supports many identity providers out of the box:
- Google (easiest for personal use — just OAuth)
- GitHub
- Microsoft / Azure AD
- One-time PIN (email verification — no external IdP needed)
- SAML providers (for organizational use)
For a personal homelab, Google OAuth or one-time PIN covers most needs:
One-Time PIN setup:
- No external configuration needed
- Cloudflare sends a numeric code to the email you specify
- Works for guests without Google/GitHub accounts
- Good for sharing access with specific people without giving them credentials
Google OAuth:
- Create an OAuth client in Google Cloud Console
- Enter the client ID and secret in Cloudflare
- Specify authorized redirect URI:
https://[your-team-domain].cloudflareaccess.com/cdn-cgi/access/callback
Policy Examples
Allow only yourself:
Rule type: Emails
Value: [email protected]
Allow your family:
Rule type: Emails
Values: [email protected], [email protected], [email protected]
Allow by email domain:
Rule type: Email domain
Value: yourdomain.com
Require MFA:
Rule type: Authentication method
Value: mfa (requires the user's IdP to have MFA enabled)
IP allowlist bypass (for trusted networks):
Rule type: IP ranges
Values: 10.0.0.0/8, 192.168.0.0/16
Action: Bypass
This lets local network access skip authentication while still protecting external access.
Like what you're reading? Subscribe to HomeLab Starter — free weekly guides in your inbox.
Practical Configuration for Common Homelab Services
Proxmox Web UI
Proxmox uses a self-signed certificate by default, which causes issues through the tunnel. Fix with a noTLSVerify option in the cloudflared config:
ingress:
- hostname: proxmox.yourdomain.com
service: https://localhost:8006
originRequest:
noTLSVerify: true
Or better: get a real cert for Proxmox using the Cloudflare API as your ACME DNS provider. Then TLS verify works cleanly.
Grafana
ingress:
- hostname: grafana.yourdomain.com
service: http://localhost:3000
Grafana handles its own auth. You get two layers: Cloudflare Access (who's allowed through) and Grafana login (what they can do inside).
Jellyfin / Plex
Media servers work through tunnels but note: Cloudflare's free tier has a bandwidth restriction for unmetered use cases. Cloudflare's ToS prohibits using tunnels to stream large amounts of video to end users. For personal viewing, it's fine. For sharing libraries with many people, consider Tailscale or a VPS instead.
SSH Access
Cloudflare can proxy SSH too, but the setup is more involved:
# In your .ssh/config on the client machine
Host ssh.yourdomain.com
ProxyCommand cloudflared access ssh --hostname %h
Then add SSH as an application type in Zero Trust. This gives you browser-based SSH access from the dashboard without installing cloudflared on client machines.
Comparing to Alternatives
| Approach | Port exposure | Setup complexity | Cost |
|---|---|---|---|
| Cloudflare Tunnel | None | Low | Free |
| Tailscale | None | Low | Free (personal) |
| WireGuard VPN | 1 port (UDP) | Medium | Free |
| Reverse proxy + DDNS | Ports 80/443 | Medium | Free |
| VPS reverse proxy | Ports 80/443 | High | $5–10/month |
Cloudflare vs Tailscale:
- Both are excellent zero-config options
- Cloudflare is better for web services with custom domains and identity-based access control
- Tailscale is better for direct TCP access (SSH, RDP, SMB) and device-to-device networking
- Many homelab users run both: Cloudflare for web UIs, Tailscale for everything else
WARP Connector (Homelab Network Routing)
Beyond tunnels for specific services, Cloudflare offers WARP Connector — a newer feature that routes all traffic from your homelab's network through Cloudflare. This is more like a traditional VPN.
# Install WARP connector on a homelab gateway machine
curl -fsSL https://pkg.cloudflareclient.com/install.sh | bash
warp-cli tunnel vnet connect [network-id]
This lets you define a private network in Cloudflare Zero Trust and access any device on it from outside, not just specifically configured tunnels. Useful for accessing arbitrary homelab IPs without pre-configuring each service.
Monitoring Tunnel Health
The Cloudflare dashboard shows tunnel status, but for local monitoring:
# Check cloudflared logs
docker logs cloudflared --tail 50
# Metrics endpoint (if enabled)
curl http://localhost:2000/metrics
Add a Prometheus scrape target for localhost:2000 and you get tunnel connectivity metrics in Grafana.
Free Tier Limits
Cloudflare Zero Trust's free tier includes:
- 50 users (applications, not seats in the traditional sense)
- Unlimited tunnels
- Unlimited public hostnames
- Basic Access policies
- One-time PIN and most OAuth providers
What the free tier excludes:
- WARP device enrollment beyond 50 devices
- Advanced CASB features
- Dedicated egress IPs
- SLA guarantees
For a personal homelab, you'll never hit free tier limits.
The Operational Reality
Running cloudflared in Docker is genuinely low-maintenance. It reconnects automatically after network interruptions, updates gracefully, and doesn't require firewall changes. The Cloudflare dashboard is good for initial setup, but most configuration can be done via the API or Terraform for infrastructure-as-code enthusiasts.
The main limitation is vendor lock-in. Your services become dependent on Cloudflare's network. If Cloudflare has an outage (rare but it happens), your homelab remote access goes with it. For critical services, keep Tailscale or a VPN as a fallback. For convenience-only access to dashboards and media, the Cloudflare dependency is an acceptable trade.
