# Running Talos Kubernetes Behind a Pangolin Tunnel

Most Kubernetes guides assume your cluster nodes are directly reachable: static public IP, clean network, wide-open ports, the usual. But sometimes life is not that simple:

* Your cluster is running **at home**, behind NAT
    
* Your home ISP gives **no public IP**
    
* Your cluster needs to be **reachable from the cloud** (CI/CD, GitOps, remote access)
    
* You want **secure, encrypted access** without exposing your whole LAN
    

That was exactly my situation and that’s where **Pangolin Tunnel** + **Talos** proved to be *the perfect combination*!

## The Setup

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1762433411385/48939b54-6a55-4be4-8762-5f7a18ff9b0d.png align="center")

---

## Why Talos?

Talos is a **minimal**, **immutable**, **API-driven** operating system for Kubernetes.  
No SSH. No shell. No package manager.  
Everything is configured via `talosctl`.

This makes it **perfect for remote, locked-down nodes** because:

* Managing security becomes ridiculously simple
    
* Configuration is declarative and version-controlled
    
* If something breaks, you replace not repair!
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1762434622112/70745af9-9c4e-42a0-9d04-23403009f622.png align="center")
    
    After spinning TalOS in VM, it is in maintenance stage unless it is configured using talosctl remotely.
    

---

## Why Pangolin?

Pangolin Tunnel creates secure, **relay-assisted overlay connections** between machines without needing to open your network to the internet or struggle with port forwarding.

Think of it like **WireGuard with NAT traversal + automatic routing + hostname access**.

In our setup:

| Port | Purpose | Where it goes |
| --- | --- | --- |
| 6443 | Kubernetes API Server | Talos VM (internal) |
| 50000 | Talos Machine API | Talos VM (internal) |

The internal IP never becomes public: Pangolin handles the transport.

---

## Steps that I followed:

### 0\. Install talosctl

```yaml
brew install siderolabs/tap/talosctl
## or
curl -sL https://talos.dev/install | sh
```

---

### 1\. Configure Talosctl to Use the Public Endpoint

```yaml
talosctl config endpoint mytunnel.nyzex.in
talosctl config node mytunnel.nyzex.in
```

---

### 2\. Generate the Cluster Configuration

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1762433870084/d39d3cec-5314-4708-94da-661da6596293.png align="center")

```yaml
talosctl gen config mycluster https://mytunnel.nyzex.in:6443
```

This creates:

```yaml
controlplane.yaml
worker.yaml
talosconfig
```

---

### 3\. Add Your Public Hostname to TLS SANs

Open `controlplane.yaml`:

```yaml
machine:
  certSANs:
    - mytunnel.nyzex.in
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1762434044985/d30074c5-06db-4266-b8be-9ae0f62babcd.png align="center")

We can preset the sans as well, this eliminates the need to edit the file! For that I used the following:

```yaml
talosctl gen config mycluster https://mytunnel.nyzex.in:6443 \
  --output ./cluster \
  --additional-sans mytunnel.nyzex.in \
  --force
```

Additionally, in this command I also used a specific path for the output files to be at.

---

### 4\. Apply the Config

```yaml
talosctl apply-config --insecure --nodes mytunnel.nyzex.in --file controlplane.yaml
```

The node will reboot automatically.

---

### 5\. Bootstrap the Cluster

```yaml
talosctl bootstrap -n mytunnel.nyzex.in
```

This initializes etcd and the Kubernetes control plane.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1762434219906/7a95e5a0-9f08-42be-86cc-d05ea653ca08.png align="center")

After some the health is fine and we are good to go!

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1762434291299/a35b8351-ffbd-4410-83bc-ff2ba6a62b5e.png align="center")

We also see the logs in the TalOS VM become healthy now!

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1762434568409/efa55206-b80f-449b-9268-155716f22268.png align="center")

---

### 6\. Merge Config and Verify

```yaml
talosctl config merge talosconfig
talosctl config endpoint mytunnel.nyzex.in
talosctl config node mytunnel.nyzex.in
talosctl config info
```

If certificate matches, you are good to go!

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1762434407068/d1423e41-356b-4e99-883f-0b5bbcf8860f.png align="center")

```yaml
talosctl version -n mytunnel.nyzex.in
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1762434423284/d467ff74-ce1a-402c-bcde-1abfc01ba060.png align="center")

---

### 7\. Get Your Kubeconfig

```yaml
talosctl kubeconfig -n mytunnel.nyzex.in .
export KUBECONFIG=$(pwd)/kubeconfig
```

Verify:

```yaml
kubectl get nodes
kubectl get pods -A
```

Output should look like:

```yaml
NAME            STATUS   ROLES           AGE     VERSION
talos-1lh-tsx   Ready    control-plane   2m24s   v1.34.1
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1762434690811/67a72603-0b2c-4377-a5a1-5b83cda90653.png align="center")

We are yet to add the worker nodes to this, perhaps we shall talk about it in a different blog!

---

## Done! Secure Remote Kubernetes, No Public LAN Exposure

You now have:

* Talos control plane
    
* Accessible remotely
    
* Over secure encrypted overlay
    
* Without exposing your home network
    
* Without static IP requirements
    
* Without painful firewall rules
    

This setup is *super homelab friendly* and production-grade secure.
