Install K3s Lightweight Kubernetes on VPS

Install K3s Lightweight Kubernetes on VPS

September 2026 · 9 min read

K3s is a lightweight, CNCF-certified Kubernetes distribution designed for resource-constrained environments like VPS servers with 1–2 GB of RAM. Unlike full Kubernetes which requires at least 2 GB just for the control plane, K3s packages the API server, scheduler, controller manager, and an embedded database into a single binary under 100 MB, and starts up with as little as 512 MB of RAM. This guide walks you through installing a K3s single-node cluster on Ubuntu 22.04/24.04, deploying your first application, and configuring the Traefik ingress controller that ships with K3s out of the box.

System Requirements

K3s runs on very modest hardware, but for a stable production setup these specs are recommended:

ComponentMinimumRecommended
RAM512 MB1–2 GB+
CPU1 vCore2 vCores+
Disk2 GB20 GB+
OSUbuntu 20.04+Ubuntu 22.04 / 24.04
# Check kernel version (requires 4.15+)
uname -r

# Check available RAM
free -h

# Check CPU cores
nproc

Install K3s (Server / Control Plane)

K3s installs with a single command. The script downloads the binary, sets up a systemd service, and starts the cluster automatically:

# Install K3s (latest stable)
curl -sfL https://get.k3s.io | sh -

# Check that the service is running
sudo systemctl status k3s

# Verify the node is Ready
sudo kubectl get nodes

After installation, K3s writes a kubeconfig to /etc/rancher/k3s/k3s.yaml. Copy it so you can use kubectl as a regular user:

# Set up kubeconfig for your user
mkdir -p ~/.kube
sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
sudo chown $(id -u):$(id -g) ~/.kube/config
export KUBECONFIG=~/.kube/config

# Confirm the cluster is reachable
kubectl cluster-info

Add Worker Nodes (Multi-Node Cluster)

To scale beyond a single node, retrieve the join token from the server and install K3s in agent mode on each worker:

# On the server node — get the token
sudo cat /var/lib/rancher/k3s/server/node-token

# On each worker node — install as agent
curl -sfL https://get.k3s.io | K3S_URL=https://SERVER_IP:6443 \
  K3S_TOKEN=NODE_TOKEN sh -

# Back on the server — verify all nodes are Ready
kubectl get nodes -o wide
Note: Open ports 6443 (API server) and 10250 (Kubelet) in your firewall between the server and worker nodes with ufw allow 6443/tcp and ufw allow 10250/tcp.

Deploy Your First Application

Test the cluster by deploying Nginx with two replicas:

# Create a deployment
kubectl create deployment nginx --image=nginx:alpine --replicas=2

# Expose it as a NodePort service
kubectl expose deployment nginx --port=80 --type=NodePort

# Check pods and service
kubectl get pods
kubectl get svc nginx

Note the assigned NodePort (e.g. 30xxx) and visit http://VPS_IP:NodePort to confirm Nginx is serving traffic.

Use the Built-in Traefik Ingress

K3s automatically installs Traefik as an ingress controller, listening on ports 80 and 443:

# Confirm Traefik is running
kubectl get pods -n kube-system | grep traefik

# View the Traefik service
kubectl get svc -n kube-system traefik

Create an Ingress resource to route traffic to the Nginx deployment above:

cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-ingress
  annotations:
    traefik.ingress.kubernetes.io/router.entrypoints: web
spec:
  rules:
  - host: nginx.yourdomain.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx
            port:
              number: 80
EOF
Tip: Point nginx.yourdomain.com DNS to your VPS IP first. Traefik will automatically route requests to the Nginx pods once the DNS propagates.

Common kubectl Commands

# List all resources in the current namespace
kubectl get all

# View pod logs
kubectl logs POD_NAME

# Open a shell inside a container
kubectl exec -it POD_NAME -- /bin/sh

# Scale a deployment
kubectl scale deployment nginx --replicas=3

# Delete a deployment
kubectl delete deployment nginx

# Apply a manifest file
kubectl apply -f app.yaml

# List pods across all namespaces
kubectl get pods -A

Persistent Storage with Local Path Provisioner

K3s ships with a Local Path Provisioner for simple persistent volumes:

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-pvc
spec:
  accessModes:
  - ReadWriteOnce
  storageClassName: local-path
  resources:
    requests:
      storage: 5Gi
EOF

# Check PVC status
kubectl get pvc

Upgrading and Uninstalling K3s

# Upgrade K3s to the latest version
curl -sfL https://get.k3s.io | sh -

# Uninstall K3s from the server node
/usr/local/bin/k3s-uninstall.sh

# Uninstall from an agent node
/usr/local/bin/k3s-agent-uninstall.sh

Verify K3s Is Working Correctly

# Check K3s service status
sudo systemctl status k3s

# Verify node status (should show Ready)
kubectl get nodes

# List all system pods in kube-system
kubectl get pods -n kube-system

# Confirm the API server responds
kubectl cluster-info

# Display K3s version
k3s --version
Tip: If a node shows NotReady, check the logs with sudo journalctl -u k3s -f. The most common cause is the CNI plugin still initialising — wait 1–2 minutes and check again before taking further action.

Troubleshooting Common Issues

Error: "node not found" or node stuck at NotReady

The CNI network plugin hasn't finished initialising, or a firewall is blocking VXLAN traffic between nodes.

# Read recent K3s logs
sudo journalctl -u k3s --no-pager | tail -50

# Check the Flannel CNI pod (default CNI in K3s)
kubectl get pods -n kube-system | grep flannel

# Open UDP 8472 for VXLAN (required for multi-node setups)
sudo ufw allow 8472/udp

Error: "x509: certificate signed by unknown authority"

The IP or hostname in your copied kubeconfig doesn't match the certificate's SAN entries.

# View the kubeconfig K3s generated (points to localhost)
sudo cat /etc/rancher/k3s/k3s.yaml

# Replace 127.0.0.1 with your VPS public IP for remote access
sed 's/127.0.0.1/VPS_PUBLIC_IP/g' /etc/rancher/k3s/k3s.yaml > ~/.kube/config

Error: "dial tcp: connection refused" on port 6443

The K3s API server isn't running, or port 6443 is blocked by the firewall.

# Check if K3s is listening on 6443
sudo ss -tlnp | grep 6443

# Restart K3s
sudo systemctl restart k3s

# Allow the port through the firewall
sudo ufw allow 6443/tcp

Pods being evicted / "Insufficient memory"

The VPS doesn't have enough RAM to schedule the requested pods. K3s evicts pods when node memory falls below eviction thresholds.

# Check allocated resources on the node
kubectl describe node | grep -A5 "Allocated resources"

# Add a 2 GB swap file to buy more headroom
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile swap swap defaults 0 0' | sudo tee -a /etc/fstab

Traefik not receiving traffic on port 80/443

The Traefik LoadBalancer service stays in Pending because standard VPS providers don't supply an external load balancer IP.

# Check Traefik service status
kubectl get svc -n kube-system traefik

# Patch the service with your VPS public IP
kubectl patch svc traefik -n kube-system \
  -p '{"spec":{"externalIPs":["VPS_PUBLIC_IP"]}}'

Frequently Asked Questions

How does K3s differ from full Kubernetes?

K3s is CNCF-certified, meaning its API and resources are identical to upstream Kubernetes. The key differences are that K3s uses SQLite instead of etcd on a single node (saving around 200 MB of RAM), bundles multiple components into one binary, and removes cloud-provider plugins that aren't needed on a VPS. The binary is roughly 10x smaller and boots much faster. For large production clusters that need etcd's write throughput, full Kubernetes is still the right choice.

Can I use Helm charts with K3s?

Yes — any Helm chart compatible with Kubernetes works on K3s without modifications. K3s also includes a built-in Helm Controller that lets you deploy charts via a HelmChart CRD without even installing the Helm CLI. If you prefer the CLI, install it the usual way: curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash.

Is K3s suitable for production?

Yes. K3s is used in production by many organizations, particularly for edge computing, IoT gateways, and small-scale Kubernetes clusters on VPS. For high availability, you can run K3s with embedded etcd across three or more server nodes: curl -sfL https://get.k3s.io | K3S_TOKEN=SECRET sh -s - server --cluster-init. Additional server nodes then join with --server https://FIRST_SERVER:6443.