I Exposed My $70 Kubernetes Cluster to the Internet (Without Opening a Single Port)
Source: Dev.to
The Problem
Locally I accessed Grafana via http://192.168.0.173:30300.
Opening ports to the internet is like leaving your front door unlocked. I didn’t want to risk a crypto‑miner running on my GTX 1070 Ti.
I needed a solution that was:
- Secure – no open ports.
- Free – staying on a budget.
- Public – reachable via
subdomain.domain.com.
Enter Cloudflare Tunnel.
The Zero Trust Switch
DNS Migration
| Old way | New way |
|---|---|
| Squarespace Registrar → Netlify DNS | Squarespace Registrar → Cloudflare DNS → Netlify (main site) + Tunnel (subdomains) |
I migrated my nameservers to Cloudflare, which automatically imported my existing records with zero downtime.
Deploying cloudflared to Kubernetes
Instead of running the binary on each node (Pop!_OS desktop, Ubuntu laptop), I deployed the tunnel connector as a native Kubernetes deployment.
apiVersion: apps/v1
kind: Deployment
metadata:
name: cloudflared
spec:
replicas: 2
template:
spec:
containers:
- name: cloudflared
image: cloudflare/cloudflared:latest
args:
- tunnel
- --no-autoupdate
- run
- --token
- $(TUNNEL_TOKEN)
Now the cluster dials out to Cloudflare automatically. If a node reboots, Kubernetes reschedules the pod and the tunnel reconnects instantly.
Goodbye NodePorts, Hello Subdomains
In the Cloudflare Dashboard (Network > Tunnels) I mapped public hostnames to internal ClusterIPs (or NodePorts):
grafana.bhargavmantha.dev → http://192.168.0.173:30300ollama.bhargavmantha.dev → http://192.168.0.173:31434uptime.bhargavmantha.dev → http://192.168.0.173:30001
SSL certificates are handled automatically by Cloudflare at the edge, so I get the padlock icon without configuring cert‑manager or Let’s Encrypt inside the cluster.
Lessons Learned
Lesson 1 – Ingress Controllers are Overkill for Homelabs
I spent days trying to get Traefik or Nginx Ingress to work with MetalLB on a bare‑metal cluster. Cloudflare Tunnel bypasses that entire layer. I don’t need an Ingress Controller; I just need a connector.
Lesson 2 – Security Can Be Convenient
By putting everything behind Cloudflare, I can later add an Access Application layer—e.g., protect grafana.bhargavmantha.dev with a Google/GitHub login screen, adding 2FA to apps that don’t support it natively.
Current State
- Publicly Accessible: Grafana, Uptime Kuma, Open WebUI.
- Cost: $0 (Cloudflare Free Tier).
- Security: 0 open ports.