k3s is a lightweight, fully conformant Kubernetes distribution that installs as a single binary. It lets you learn Kubernetes, or run a handful of real services, on one VPS or a small group of them. This guide covers a single-node install, a multi-node cluster, HTTPS ingress with Let's Encrypt, Helm, storage, monitoring and backups on a Domain India VPS.
k3s gives you standard Kubernetes (kubectl, YAML manifests, Helm charts) with far less overhead than a full kubeadm cluster. Plan on at least 2 GB of RAM for a server node and 4 GB once you add monitoring. It needs root access, so it runs on a VPS, not on shared hosting. Install with one command, keep the API port private, and back up the datastore and the join token.
1. Why k3s instead of full Kubernetes
A kubeadm cluster runs etcd and several separate control-plane components, which is heavy for a single small server. k3s packages the essentials into one binary:
- a single binary of well under 100 MB;
- SQLite as the default datastore on a single server, with embedded etcd available for high availability;
- a built-in service load balancer, the Traefik ingress controller and a local storage provisioner;
- the same
kubectl, the same manifests and the same Helm charts as any other conformant Kubernetes.
k3s is a CNCF project, originally created by Rancher (now part of SUSE). The k3s documentation gives 2 GB of RAM as the minimum for a server node and 512 MB for an agent (worker) node.
2. When to use k3s
| Use case | Good fit? |
|---|---|
| Learning Kubernetes | Excellent |
| Small production app (1-5 services) | Good |
| Edge and small-device deployments | Designed for it |
| Large microservice estates (hundreds of pods, many teams) | Consider RKE2, upstream Kubernetes or a managed service |
If you only need to run one app, a container on a plain VPS or the Domain India App Platform is simpler. Choose k3s when you want Kubernetes itself: several services, rolling deployments, Helm charts or practice for a Kubernetes job.
3. Single-node setup
Order a VPS with at least 4 GB of RAM if you plan to add monitoring, and choose Ubuntu 24.04 LTS or AlmaLinux 9 (or a newer LTS release if your OS list offers one). Choose no control panel: a panel's web server would take ports 80 and 443, which Traefik needs.
- Connect as root over SSH.
- Open the firewall for k3s.Keep your firewall on and add the rules below rather than disabling it.
- Install k3s. Run `curl -sfL https://get.k3s.iosh -
. The installer sets up a systemd service calledk3s`. - Check the node.Run
sudo kubectl get nodes. The node should showReadywithin a minute. - Use kubectl from your computer (optional).Copy
/etc/rancher/k3s/k3s.yamlto~/.kube/configon your computer and replace127.0.0.1in theserver:line with your VPS IP. Only do this if port 6443 is restricted to your own IP address.
Firewall rules on AlmaLinux (firewalld):
sudo firewall-cmd --permanent --add-port=80/tcp
sudo firewall-cmd --permanent --add-port=443/tcp
sudo firewall-cmd --permanent --zone=trusted --add-source=10.42.0.0/16 # pods
sudo firewall-cmd --permanent --zone=trusted --add-source=10.43.0.0/16 # services
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="YOUR.OFFICE.IP/32" port port="6443" protocol="tcp" accept'
sudo firewall-cmd --reloadOn Ubuntu (ufw):
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow from 10.42.0.0/16 to any
sudo ufw allow from 10.43.0.0/16 to any
sudo ufw allow from YOUR.OFFICE.IP to any port 6443 proto tcp
sudo ufw enableCheck the node:
sudo kubectl get nodes
# NAME STATUS ROLES AGE VERSION
# your-vps-name Ready control-plane,master 30s v1.xx.x+k3s1The k3s service runs as root and the admin kubeconfig has full cluster rights. If other people will use the cluster, give them namespaces and RBAC roles instead of copying k3s.yaml. A rootless mode exists but has limitations; read the k3s documentation before using it.
4. Deploy your first app
Create app.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello
spec:
replicas: 2
selector:
matchLabels: { app: hello }
template:
metadata:
labels: { app: hello }
spec:
containers:
- name: hello
image: nginxdemos/hello:latest
ports:
- containerPort: 80
resources:
requests:
memory: 64Mi
cpu: 50m
limits:
memory: 128Mi
cpu: 100m
---
apiVersion: v1
kind: Service
metadata:
name: hello
spec:
selector: { app: hello }
ports:
- port: 80
targetPort: 80Apply it:
sudo kubectl apply -f app.yaml
sudo kubectl get pods
# hello-7c5cbb5d4f-abc12 1/1 Running 0 10s
# hello-7c5cbb5d4f-def34 1/1 Running 0 10sIn production, pin images to a specific version tag instead of latest.
5. Install Helm
Helm installs packaged applications ("charts") such as cert-manager, Prometheus and Longhorn:
curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
helm versionA newer Helm major version may be available; check the Helm website. Charts from the Bitnami catalogue changed their free-image terms in 2025, so check a chart's image source and update policy before you rely on it. For a gentle introduction, see Helm charts for beginners.
6. HTTPS ingress with Traefik and Let's Encrypt
k3s ships with the Traefik ingress controller listening on ports 80 and 443. The most portable way to get Let's Encrypt certificates is cert-manager, which works the same whichever Traefik version your k3s release bundles.
Install cert-manager:
helm repo add jetstack https://charts.jetstack.io
helm repo update
helm install cert-manager jetstack/cert-manager \
--namespace cert-manager --create-namespace \
--set crds.enabled=trueCreate a Let's Encrypt issuer, issuer.yaml:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: [email protected]
privateKeySecretRef:
name: letsencrypt-account-key
solvers:
- http01:
ingress:
ingressClassName: traefikThen define your Ingress, ingress.yaml:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: hello
annotations:
cert-manager.io/cluster-issuer: letsencrypt
spec:
ingressClassName: traefik
rules:
- host: hello.yourcompany.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: hello
port: { number: 80 }
tls:
- hosts: [hello.yourcompany.com]
secretName: hello-tlsPoint an A record for hello.yourcompany.com at your VPS IP, then apply both files with sudo kubectl apply -f. cert-manager requests the certificate once DNS resolves; sudo kubectl get certificate shows READY True when it is issued. To redirect HTTP to HTTPS, add a Traefik redirectScheme middleware to the Ingress.
7. Multi-node cluster
For more capacity, add worker (agent) nodes. On the first server, read the join token:
sudo cat /var/lib/rancher/k3s/server/node-tokenOn each worker VPS:
curl -sfL https://get.k3s.io | \
K3S_URL=https://<server-ip>:6443 \
K3S_TOKEN=<token-from-server> \
sh -Then check from the server with sudo kubectl get nodes.
Nodes talk to each other over the flannel network: UDP 8472 for the default VXLAN backend. That traffic is not encrypted and the port must never be open to the whole internet. When your nodes connect over public IPs, install every node with --flannel-backend=wireguard-native (UDP 51820 between nodes), and allow the node ports only from your other nodes' IPs. Workers must also reach the server on TCP 6443.
High-availability control plane (optional)
Three server nodes with embedded etcd keep the cluster running if one server fails. Pick a long random token, then:
# First server
curl -sfL https://get.k3s.io | K3S_TOKEN=<shared-secret> sh -s - server --cluster-init
# Second and third servers
curl -sfL https://get.k3s.io | K3S_TOKEN=<shared-secret> sh -s - server \
--server https://<first-server-ip>:6443The servers must reach each other on TCP 2379-2380 for etcd. Use an odd number of servers (3 or 5). As an alternative, k3s can use an external PostgreSQL or MySQL datastore with --datastore-endpoint instead of embedded etcd.
8. Persistent storage
k3s includes the local-path storage class, which stores volumes on the node's own disk:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: app-data
spec:
accessModes: [ReadWriteOnce]
storageClassName: local-path
resources:
requests: { storage: 5Gi }A local-path volume lives on one node, so a pod that uses it can only run there. For replicated storage across several nodes, Longhorn is a common choice with k3s. It needs open-iscsi on every node and is most useful with three or more nodes:
helm repo add longhorn https://charts.longhorn.io
helm repo update
helm install longhorn longhorn/longhorn --namespace longhorn-system --create-namespace9. Monitoring with Prometheus and Grafana
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
helm install monitoring prometheus-community/kube-prometheus-stack \
--namespace monitoring --create-namespaceThis stack uses a lot of memory; on a 4 GB node leave room for your apps and set resource limits. Open Grafana through a port-forward rather than exposing it:
sudo kubectl -n monitoring port-forward svc/monitoring-grafana 3000:80
sudo kubectl -n monitoring get secret monitoring-grafana \
-o jsonpath="{.data.admin-password}" | base64 -dDon't expose Grafana as a LoadBalancer service on a single node: k3s's built-in load balancer would try to bind port 80, which Traefik already uses. For logs and alerting, see production observability with Prometheus, Grafana and Loki.
10. Backups
Back up the cluster datastore, the server token and your persistent volumes.
- Single server (SQLite): the state is in
/var/lib/rancher/k3s/server/db/. Copy it while k3s is stopped, or withsqlite3 state.db ".backup /root/state-backup.db", and also keep/var/lib/rancher/k3s/server/token: a restored datastore is useless without it. - Embedded etcd: k3s takes etcd snapshots automatically; run
sudo k3s etcd-snapshot savefor an on-demand one before upgrades. - Volumes: back up
local-pathdata under/var/lib/rancher/k3s/storage/, or use Longhorn's backup feature.
A nightly example that ships an archive off the server with rclone. Save it as /root/k3s-backup.sh and make it executable:
#!/bin/sh
set -e
tar czf /root/k3s-backup.tgz \
/var/lib/rancher/k3s/server/db \
/var/lib/rancher/k3s/server/token \
/var/lib/rancher/k3s/storage
rclone copy /root/k3s-backup.tgz remote:k3s-backups/Then run it from root's crontab with 0 3 * * * /root/k3s-backup.sh. See our automated backups guide for rclone setup, and test a restore before you rely on it.
11. Security hardening
- Keep the API private. Allow port 6443 only from your own IPs and your other nodes, never from everywhere.
- Use RBAC. It is on by default; give people namespace roles, not cluster-admin.
- Restrict pod traffic with NetworkPolicies; k3s enforces them out of the box.
- Scan images for known vulnerabilities, for example with
trivy image your-app:1.2.3. - Keep k3s updated. Re-run the installer with the same options (or put them in
/etc/rancher/k3s/config.yaml), pinning a release withINSTALL_K3S_VERSIONor followingINSTALL_K3S_CHANNEL=stable. Upgrade servers before agents, one minor version at a time. - Harden the VPS itself. See the VPS security checklist.
12. Common pitfalls
/var/lib/rancher/k3s/agent/containerd/. Remove unused images with sudo k3s crictl rmi --prune./usr/local/bin/k3s-uninstall.sh (or k3s-agent-uninstall.sh on workers), not manual deletion.13. Running k3s on Domain India
k3s needs root access and its own ports, so it runs on a Domain India VPS, not on shared hosting. Our VPS plans are self-managed KVM servers with full root access: you install and look after k3s yourself, and cPanel is not offered on VPS. For a cluster with monitoring, start with at least 4 GB of RAM.
- 2 vCPU
- 4 GB DDR4 RAM
- 128 GB NVMe SSD Storage
- 3 TB Monthly Bandwidth
The plan card shows the Domain India list price, excluding 18% GST. If you just want to deploy one app from a Git repository without running Kubernetes yourself, look at the App Platform.
Frequently asked questions
Can I use the same kubectl commands I learned on EKS or GKE?
Yes. k3s is a conformant Kubernetes distribution, so kubectl, manifests and Helm charts work the same way. Features tied to a cloud provider, such as its load balancers and storage drivers, are different.
Does k3s work with public container images?
Yes. It pulls from Docker Hub, GitHub Container Registry and other registries. For private registries, create an image pull secret or configure /etc/rancher/k3s/registries.yaml.
Can I migrate from k3s to another Kubernetes distribution later?
Yes. Your manifests and Helm charts move across. You may need to change storage classes and the ingress controller to match the new cluster.
How much RAM does k3s need?
The k3s documentation gives 2 GB as the minimum for a server node and 512 MB for an agent node. With Prometheus, Grafana and your own apps, plan on 4 GB or more.
Can I run k3s on shared hosting?
No. k3s needs root access, its own system service and its own network ports, which shared hosting does not provide. Use a VPS, or the App Platform if you only need to run an app.
How do k3s, MicroK8s and minikube compare?
k3s is a lightweight distribution built for production and edge use. MicroK8s is Canonical's snap-based distribution. minikube is designed for local development and testing, not production.
Ready to build your cluster? Compare our VPS plans, read how to access your VPS using SSH, or open a support ticket if you have a question about your server.
Self-managed KVM VPS with full root access, ready for k3s, Docker and your own tools.
See VPS plans