K3s in the Real World: Install, Break, Fix, Repeat
A practical field guide to K3s — installation on Linux and Windows, kubeconfig setup, Lens connectivity, force-deleting stuck namespaces, and certificate rotation when your cluster's TLS finally expires.
K3s is what Kubernetes looks like when you strip out everything that isn't essential — a single binary, sub-100MB memory footprint, and a cluster that's production-usable in under a minute. It's the go-to choice for edge deployments, small VMs, homelabs, and any environment where a full kubeadm cluster would be overkill.
Quick Install (Default)
The fastest path to a running cluster:
curl -sfL https://get.k3s.io | sh -
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
That's it — a single-node K3s cluster with a bundled Traefik ingress controller, local-path storage provisioner, and containerd runtime.
Production-Style Install
For anything beyond a throwaway VM, you'll usually want more control: disabling the bundled Traefik (if you're running your own), setting the correct TLS SAN for external access, and fixing kubeconfig permissions.
curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--disable=traefik" sh -s - \
server \
--write-kubeconfig-mode 644 \
--tls-san <your-vm-public-ip>
Replace
<your-vm-public-ip>with the actual IP or hostname you'll use to reach the API server — this must be baked in at install time or the server certificate won't validate for that address.
Long-Lived Certificates
By default, K3s issues certs with a relatively short validity window. If you'd rather not deal with rotation for a decade, extend the signing duration at install time:
curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--disable=traefik" sh -s - \
server \
--write-kubeconfig-mode 644 \
--tls-san <your-vm-public-ip> \
--kube-apiserver-arg=--experimental-cluster-signing-duration=87600h
Persist KUBECONFIG
Add it to your shell profile so it survives new sessions:
echo 'export KUBECONFIG=/etc/rancher/k3s/k3s.yaml' >> ~/.bashrc
source ~/.bashrc
Firewall Ports (RHEL / RHEL10)
K3s needs a specific set of ports open for API access, etcd (if used), VXLAN overlay networking, kubelet, NodePort services, and WireGuard (if enabled as the CNI backend):
for p in 6443/tcp 2379-2380/tcp 8472/udp 10250/tcp 30000-32767/tcp 51820/udp 51821/udp; do
firewall-cmd --permanent --add-port=$p
done
firewall-cmd --reload
firewall-cmd --list-ports
Connecting Lens (or Other GUI Clients)
Lens and similar tools authenticate against the cluster using a serving certificate. If Lens can't connect, check the k3s-serving secret:
kubectl edit secret k3s-serving -n kube-system
Make sure the SANs in that secret actually include the address you're connecting from — if you didn't set --tls-san at install time, this is usually where the mismatch shows up.
Force-Deleting a Stuck Namespace
Namespaces occasionally get stuck in Terminating because a resource inside still has a finalizer blocking cleanup. Here's how to clear it manually:
Step 1 — Dump the namespace as JSON:
kubectl get namespace <namespace-name> -o json > ns.json
Step 2 — Edit ns.json and empty the finalizers list:
"spec": {
"finalizers": []
}
Step 3 — Push the modified spec directly to the finalize subresource:
kubectl replace --raw "/api/v1/namespaces/<namespace-name>/finalize" -f ns.json
Use this as a last resort — a finalizer usually exists because something (a controller, an operator, a webhook) needs to run cleanup logic first. Force-deleting can leave orphaned cloud resources or dangling records behind.
Certificate Management
Check Certificate Expiry
openssl x509 -in /var/lib/rancher/k3s/server/tls/server-ca.crt -text -noout | grep "Not After"
Regenerate Expired Certificates (Manual Method)
If the cluster CA has already expired and the API server won't come back up:
# 1. Stop K3s
sudo systemctl stop k3s
# 2. Remove only the certs — leave the raft/db and kubeconfig alone
sudo rm -f /var/lib/rancher/k3s/server/tls/*.crt
sudo rm -f /var/lib/rancher/k3s/server/tls/*.key
# 3. Start K3s — it regenerates missing certs automatically
sudo systemctl start k3s
Do not delete
/var/lib/rancher/k3s/server/db/— that's your cluster state. And leave/etc/rancher/k3s/k3s.yamlalone unless you're resetting the entire cluster.
If the API server address changed and your local kubeconfig still points at 127.0.0.1:
sudo sed -i 's/127.0.0.1/<your-node-ip>/g' /etc/rancher/k3s/k3s.yaml
Then copy the updated file to your workstation and point kubectl/Lens at it.
Certificate Rotation (Built-in Command)
Newer K3s versions ship a proper rotate command instead of manual deletion — safer, since it backs up nothing for you, so back it up yourself first:
# 1. Stop K3s
systemctl stop k3s
# 2. Back up existing certs before touching anything
cp -r /var/lib/rancher/k3s/server/tls /opt/k3s-cert-backup/tls.bak.$(date +%F)
# 3. Remove old certs
rm -f /var/lib/rancher/k3s/server/tls/*.crt
rm -f /var/lib/rancher/k3s/server/tls/*.key
# 4. Rotate
k3s certificate rotate
# 5. Verify new validity dates
openssl x509 -in /var/lib/rancher/k3s/server/tls/server-ca.crt -noout -dates
# 6. Start K3s back up
systemctl start k3s
Running K3s on Windows (WSL + Rancher Desktop)
K3s itself is Linux-only, but Rancher Desktop gives you a fully managed K3s cluster inside WSL2 — kubeconfig handled automatically, no manual cert wrangling.
Step 1 — Install WSL and a Debian Distro
wsl --install -d Debian
Already have WSL? Just make sure it defaults to v2:
wsl --set-default-version 2
Reboot if prompted, then launch Debian from the Start Menu to finish first-time user setup.
Step 2 — Install Rancher Desktop
Download from rancherdesktop.io, run the installer, then in Kubernetes Settings:
- Kubernetes distribution: K3s
- Container Runtime: containerd (or dockerd)
- Version: latest is fine
Click Apply & Restart — Rancher Desktop provisions and manages the K3s cluster inside WSL for you.
Step 3 — Install kubectl.exe
mkdir %USERPROFILE%\kubectl-tools
curl.exe -Lo %USERPROFILE%\kubectl-tools\kubectl.exe "https://dl.k8s.io/release/v1.33.0/bin/windows/amd64/kubectl.exe"
setx PATH "%PATH%;%USERPROFILE%\kubectl-tools"
Restart your shell to pick up the updated PATH.
Step 4 — Verify
kubectl version --client
kubectl get nodes
A node listed from Rancher Desktop confirms everything is wired up correctly. Rancher Desktop manages KUBECONFIG automatically — you'll typically find it at %USERPROFILE%\.kube\config.
Summary
| Task | Command |
|---|---|
| Install K3s | curl -sfL https://get.k3s.io \| sh - |
| Set kubeconfig | export KUBECONFIG=/etc/rancher/k3s/k3s.yaml |
| Check cert expiry | openssl x509 -in .../server-ca.crt -noout -dates |
| Rotate certs | k3s certificate rotate |
| Force-delete namespace | kubectl replace --raw ".../finalize" -f ns.json |
| Windows cluster | Rancher Desktop (K3s backend) via WSL2 |
Golden rule: back up /var/lib/rancher/k3s/server/tls and never touch /var/lib/rancher/k3s/server/db/ when troubleshooting certificates — the database is your cluster's memory; the certs are just its ID card.