I Exposed My $70 Kubernetes Cluster to the Internet (Without Opening a Single Port)

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • MyrinNew
    Senior Member
    • Feb 2024
    • 5168

    #1

    I Exposed My $70 Kubernetes Cluster to the Internet (Without Opening a Single Port)

    In my previous post, I talked about how I built a 3-node Kubernetes cluster for ₹6,000 ($70) to host my AI models and home lab. It worked great, but there was one ugly problem: Networking.


    The Problem

    Accessing my services meant one of two things:


    Locally: Typing http://192.168.0.173:30300 for Grafana. Ugly, but works.

    Remotely: Setting up WireGuard or Tailscale. Secure, but I can't ask my friends to install a VPN client just to see a dashboard or chat with my LLM.

    I considered opening ports on my router (Port Forwarding) pointing to an Nginx Proxy Manager. Bad idea. Opening ports to the internet is like leaving your front door unlocked because you lost your keys. I didn't want to wake up to a crypto-miner running on my GTX 1070 Ti.


    I needed a solution that was:
    • Secure (No open ports).
    • Free (I'm still on a budget).
    • Public (Accessible via subdomain.domain.com).


    Enter Cloudflare Tunnel.

    What I Did

    1. The Zero Trust Switch

      I realized Cloudflare provides a "Zero Trust" plan that is completely free for up to 50 users. This includes Tunnels. A tunnel creates an outbound-only connection from your cluster to Cloudflare's edge network. Traffic flows out to Cloudflare, then back in to your services. No inbound ports needed on my router.
    2. DNS Migration

      My domain (bhargavmantha.dev) was hosting a static site on Netlify. To use Tunnels effectively, I needed Cloudflare to manage the DNS.
    • Old way: Squarespace Registrar -> Netlify DNS.
    • New way: Squarespace Registrar -> Cloudflare DNS -> Netlify (for main site) + Tunnel (for subdomains).


    I migrated my nameservers to Cloudflare, which automatically imported my existing records. Zero downtime.

    1. Deploying cloudflared to K8s
      Instead of running a binary on my variety of nodes (Pop!_OS desktop, Ubuntu laptop), I deployed the tunnel connector as a native Kubernetes deployment.


    I created a simple manifest

    cloudflared.yaml

    that takes a token (from the Cloudflare dashboard) and runs 2 replicas for high availability.






    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, my cluster dials out to Cloudflare automatically. If I reboot a node, K8s reschedules the pod, and the tunnel reconnects instantly.

    1. Goodbye NodePorts, Hello Subdomains
      This is the magic part. In the Cloudflare Dashboard (Network > Tunnels), I simply mapped public hostnames to my internal ClusterIPs (or NodePorts).





    SSL certificates are handled automatically by Cloudflare at the edge. I get the padlock icon without setting up cert-manager or LetsEncrypt inside my cluster.


    What I Learned

    Lesson 1: Ingress Controllers are Overkill for Homelabs. I spent days trying to get Traefik or Nginx Ingress to play nice with MetalLB on a bare-metal cluster. Cloudflare Tunnel bypassed 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 also add an "Access Application" layer later—meaning I can put grafana.bhargavmantha.dev behind a Google/GitHub logic screen, adding 2FA to apps that don't even support it natively.


    Current State

    Now my cheap K8s cluster feels like a production cloud environment.


    Publicly Accessible: Grafana, Uptime Kuma, and Open WebUI.

    Cost: still $0 (Cloudflare Free Tier).

    Security: 0 Open Ports.




    More...
Working...