When running Kubernetes at home or on bare metal, one of the biggest challenges is networking. How do you make your apps reachable, both inside your local network and from outside, without adding layers of complexity or security risks?
That’s where MetalLB and Tailscale come in. Together, they give you the best of both worlds:

🔹 MetalLB gives your Kubernetes cluster the power to assign external IPs to services , just like a cloud load balancer, but made for bare metal. This makes your apps easily reachable within your private network (LAN), without needing any special hardware or cloud services.
🔹 Tailscale, on the other hand, helps you reach those same apps from anywhere, securely , without exposing them to the open internet. It creates an encrypted, peer-to-peer network that connects your devices and your cluster as if they were on the same local network.
👉 And that’s exactly what we’re going to set up in this new chapter of the series.
If you’re just joining in, this series documents how I built a fully functional Kubernetes cluster from scratch, turning theory into hands-on practice, one piece at a time.
Here’s a quick recap of what we’ve done so far:
Part 1: Building the cluster from scratch using a Raspberry Pi.
Part 2: Setting up persistent storage with Longhorn and MinIO.
Part 3: Adding monitoring and observability with Prometheus and Grafana.
Today, we’re enhancing our networking by deploying two essential tools: MetalLB and Tailscale. MetalLB provides easy, reliable load balancing within your private network, while Tailscale securely exposes your services remotely without direct public exposure.
1. Understanding Tailscale
Tailscale is a secure, zero-configuration VPN built on WireGuard technology, designed to simplify networking and securely connect devices and applications across the internet. It creates a mesh network where devices directly communicate over encrypted tunnels.
Key Capabilities of Tailscale:
- Secure VPN: End-to-end encryption with WireGuard.
- Easy Setup: Minimal configuration and rapid deployment.
- Secure Remote Access: Safely access your Kubernetes services from anywhere.
- Automatic Security: Handles authentication and key rotation automatically.
- Tailscale Funnel: Publicly accessible URLs securely exposing your internal services without direct IP exposure.

Why Tailscale for Kubernetes?
Exposing your Kubernetes cluster can be complex and risky. Methods like port forwarding, NodePorts, or manual VPNs often require tricky firewall configurations and introduce security concerns.
Tailscale simplifies this. It creates a secure, peer-to-peer network so you can access your apps remotely as if you were on the same LAN, no public exposure, minimal setup, and strong security across devices.
Other common approaches (and why they fall short):
- Port Forwarding: Directly exposes your internal network, increasing risk.
- NodePort / LoadBalancer: Often requires static IPs and detailed firewall rules.
- Manual VPN: Secure, but usually difficult to configure and maintain.

2. Deploying MetalLB
MetalLB is a powerful load balancer for Kubernetes clusters, designed to provide LoadBalancer functionality within private networks, something Kubernetes does not support natively in bare-metal or non-cloud environments.
MetalLB simplifies service exposure within the cluster by assigning internal IP addresses, streamlining traffic management, and enhancing reliability.

Image Source: Spectro Cloud — Getting Started with MetalLB: The Bare-Metal Load Balancer for Kubernetes
Start by deploying MetalLB using Helm:
helm repo add metallb https://metallb.github.io/metallbhelm repo updatehelm install metallb metallb/metallb --namespace metallb-system --create-namespace
Configure a pool of IP addresses (metallb-config.yaml) for MetalLB:
apiVersion: metallb.io/v1beta1kind: IPAddressPoolmetadata: name: default-pool namespace: metallb-systemspec: addresses: - 192.168.1.100-192.168.1.110---apiVersion: metallb.io/v1beta1kind: L2Advertisementmetadata: name: l2-advertisement namespace: metallb-system
Apply the configuration and check the pod status:
kubectl apply -f metallb-config.yamlkubectl get pods -n metallb-system
Example Output:
NAME READY STATUS RESTARTS AGEcontroller-6c7b8f957d-2p7rw 1/1 Running 0 30sspeaker-dnqgz 1/1 Running 0 30sspeaker-hz9qw 1/1 Running 0 30s
3. Deploying Tailscale for Secure Ingress
Step 1: Generate and Store Tailscale Auth Key
First, generate an Auth Key from your Tailscale Admin Console to securely join the cluster to your Tailscale network.
Create a secret manifest (tailscale-auth.yaml):
apiVersion: v1kind: Secretmetadata: name: tailscale-auth namespace: tailscalestringData: TS_AUTHKEY: tskey-auth-kE2dReML1511CNTRL-NL2Wg1SLa8MZBuaohnXTG
Apply the secret:
kubectl apply -f tailscale-auth.yaml
Step 2: Deploy Tailscale Kubernetes Operator
Next, generate OAuth credentials in the Tailscale dashboard (required for Ingress support). You’ll get a Client ID and Client Secret.
- Client ID:
kh5htVzE1ABCD - Client Secret:
tskey-client-ko5htB11CNTRL-gAHCWhYhBnb9Ee

Install the Tailscale Operator with Helm:
helm repo add tailscale https://pkgs.tailscale.com/helmchartshelm repo updatehelm upgrade --install tailscale-operator tailscale/tailscale-operator \ --namespace=tailscale \ --create-namespace \ --set-string oauth.clientId=your-client-id \ --set-string oauth.clientSecret=your-client-secret \ --wait
Replace the clientId and clientSecret with your actual values.
Check the operator is running:
kubectl get pods -n tailscale
Step 3: Configure Tailscale Ingress
Now let’s expose an app using Tailscale Funnel. For this demo, we’ll use Uptime Kuma, a simple and user-friendly monitoring tool. We’ll expose it securely using Tailscale ingress:
apiVersion: networking.k8s.io/v1kind: Ingressmetadata: name: ingress-kuma namespace: uptime-kuma annotations: tailscale.com/funnel: "true" # <- Here we set truespec: ingressClassName: tailscale # <- Here we add tailscale ! defaultBackend: service: name: uptime-kuma port: number: 80 tls: - hosts: - uptime-kuma
Apply it:
kubectl apply -f ingress-kuma.yaml
And check the external URL:
kubectl get ingress -n uptime-kumaNAME CLASS HOSTS ADDRESS PORTS AGEuptime-kuma tailscale * uptime-kuma.xxx.ts.net 80, 443 7m53s# check access ingresscurl https://uptime-kuma.xxx.ts.net
Conclusion
We’ve just set up MetalLB for internal load balancing and Tailscale for secure, remote access, two powerful tools that greatly simplify networking in your Kubernetes homelab. This setup improves reliability, reduces complexity, and keeps your applications accessible and safe.
There’s more to come! Stay tuned for the next posts in the Kubernetes Homelab Series, where we’ll keep exploring practical tools and techniques to level up your cluster.
If you’re working on your own Kubernetes homelab, let’s connect on LinkedIn and learn together!