k3s Setup

Overview

Installs a single-node k3s cluster on the VPS. k3s bundles containerd, CoreDNS, Traefik, ServiceLB, metrics-server, and the local-path storage provisioner, which is a good baseline for a small GitOps cluster.

Prerequisites

  • VPS hardening is complete
  • At least 2 vCPU, 4 GB RAM, and 30 GB free disk
  • Ports 80 and 443 are reachable; restrict 6443 to a trusted IP if remote kubectl is required

Procedure

1. Install k3s

Pin a tested release in production instead of following the newest release implicitly:

curl -sfL https://get.k3s.io | INSTALL_K3S_CHANNEL=stable sh -
sudo systemctl status k3s --no-pager

Keep bundled Traefik. Do not install ingress-nginx unless Traefik is disabled at install time; two ingress controllers make routing and ports harder to reason about.

2. Configure kubectl for the administrative user

mkdir -p ~/.kube
sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
sudo chown "$USER:$USER" ~/.kube/config
chmod 600 ~/.kube/config

For remote access, copy this file to the local machine and replace 127.0.0.1 with the VPS IP. Treat it as a secret because it contains cluster-admin credentials.

3. Handle UFW

k3s networking creates rules outside UFW. On a single node, keep public inbound access limited to SSH and HTTP(S), and allow the API only from the operator IP:

sudo ufw delete allow 6443/tcp
sudo ufw allow from <ADMIN_PUBLIC_IP> to any port 6443 proto tcp

Multi-node clusters require additional node-to-node rules and are outside this guide.

Verification

kubectl get nodes -o wide
kubectl get pods -A
kubectl get storageclass

Expected: one Ready node, system pods running, and local-path marked as the default StorageClass.

Operations

sudo journalctl -u k3s -f
sudo systemctl restart k3s

Back up /var/lib/rancher/k3s/server/token and application data. A local-path PersistentVolume is not a backup and is lost with the VPS disk.