k3s is a fully conformant Kubernetes distribution packaged as a single binary. It bundles containerd, a network plugin (Flannel), an ingress controller (Traefik), a local storage provisioner and a service load balancer — so a working cluster takes one command. It runs well on a single small VPS, which makes it ideal for learning, small production workloads, edge sites and homelabs.

Requirements

  • A Linux VPS on KVM (Ubuntu, Debian, AlmaLinux, Rocky…).
  • 1 vCPU and 1 GB RAM minimum for a server node; 2 GB+ is comfortable once you deploy apps.
  • Open ports between nodes: 6443/tcp (API), 8472/udp (Flannel VXLAN), 10250/tcp (kubelet). Publicly: only 80/443 for your apps.

1. Install a single-node cluster

curl -sfL https://get.k3s.io | sh -

The script installs k3s as a systemd service. Check:

sudo k3s kubectl get nodes
sudo systemctl status k3s --no-pager

k3s writes the kubeconfig to /etc/rancher/k3s/k3s.yaml. To use kubectl as a regular user:

mkdir -p ~/.kube
sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
sudo chown $USER: ~/.kube/config
kubectl get pods -A

Pin a version or channel for predictability: curl -sfL https://get.k3s.io | INSTALL_K3S_CHANNEL=stable sh -.

2. Add worker nodes (optional)

On the server, get the join token:

sudo cat /var/lib/rancher/k3s/server/node-token

On each worker:

curl -sfL https://get.k3s.io | K3S_URL=https://10.0.0.10:6443 K3S_TOKEN=<token> sh -

Use private/VPN addresses between nodes. If nodes communicate over the public internet, consider k3s’s built-in WireGuard backend for Flannel (--flannel-backend=wireguard-native) to encrypt pod traffic.

3. Deploy an app with an ingress

k3s includes Traefik as the ingress controller, listening on ports 80 and 443.

# whoami.yaml
apiVersion: apps/v1
kind: Deployment
metadata: { name: whoami }
spec:
  replicas: 2
  selector: { matchLabels: { app: whoami } }
  template:
    metadata: { labels: { app: whoami } }
    spec:
      containers:
        - name: whoami
          image: traefik/whoami
          ports: [{ containerPort: 80 }]
---
apiVersion: v1
kind: Service
metadata: { name: whoami }
spec:
  selector: { app: whoami }
  ports: [{ port: 80, targetPort: 80 }]
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata: { name: whoami }
spec:
  rules:
    - host: whoami.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend: { service: { name: whoami, port: { number: 80 } } }
kubectl apply -f whoami.yaml
curl -H "Host: whoami.example.com" http://<server-ip>/

Point DNS at the server and the app is live on HTTP.

4. HTTPS with cert-manager

kubectl apply -f https://github.com/cert-manager/cert-manager/releases/latest/download/cert-manager.yaml

Create a Let’s Encrypt ClusterIssuer (HTTP-01 via Traefik), then add cert-manager.io/cluster-issuer and a tls: section to your Ingress. Full walkthrough: cert-manager on Kubernetes.

5. Persistent storage

k3s’s local-path provisioner creates volumes on the node’s disk automatically:

apiVersion: v1
kind: PersistentVolumeClaim
metadata: { name: data }
spec:
  accessModes: [ReadWriteOnce]
  storageClassName: local-path
  resources: { requests: { storage: 5Gi } }

Data lives under /var/lib/rancher/k3s/storage/ on that node — back it up, and remember it doesn’t move if the pod is rescheduled to another node. For multi-node redundancy, look at Longhorn. See Kubernetes persistent volumes.

6. Access the cluster from your laptop

Copy /etc/rancher/k3s/k3s.yaml to your machine, replace 127.0.0.1 with the server address, and save it as ~/.kube/config. Better: don’t expose port 6443 publicly — reach it over a VPN like Tailscale or an SSH tunnel (ssh -L 6443:127.0.0.1:6443 user@server).

7. Disable bundled components (optional)

Prefer ingress-nginx or your own load balancer?

curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--disable traefik --disable servicelb" sh -

8. Backups and upgrades

  • Single-server k3s uses SQLite in /var/lib/rancher/k3s/server/db/; back it up along with the node token. With embedded etcd (HA mode), use k3s etcd-snapshot.
  • Keep manifests in Git (GitOps with Argo CD) so the cluster can be rebuilt.
  • Upgrade by re-running the install script with a newer version, one node at a time, or use the system-upgrade-controller.

Uninstall

/usr/local/bin/k3s-uninstall.sh          # server
/usr/local/bin/k3s-agent-uninstall.sh    # worker

k3s vs kubeadm vs Docker Compose

  • Docker Compose — simplest for one server.
  • k3s — real Kubernetes with minimal overhead; great for 1–10 nodes.
  • kubeadm — standard upstream setup, more moving parts.

See Kubernetes vs Docker Compose. A 2–4 GB KVM VPS runs a single-node k3s cluster with several small apps comfortably.

  • k3s
  • Kubernetes
  • DevOps