How to install Kubernetes Lite/K3s on Debian 13
This guide installs K3s on Debian 13 and covers:
- Single-node K3s
- 3-server High Availability cluster
- Embedded etcd
- Worker/agent nodes
- Fixed API/load-balancer address
- Firewall requirements
- Kubeconfig access
- Cluster verification
- Service management
- Uninstallation
K3s provides an official one-line installation script at get.k3s.io. The installer configures K3s as a systemd service and installs utilities including kubectl, crictl, and ctr. (K3s Documentation)
Architecture
Single-Node
┌───────────────────────────────┐
│ k3s-server-01 │
│ │
│ Kubernetes API │
│ Scheduler │
│ Controller Manager │
│ SQLite │
│ containerd │
│ Flannel │
│ Workloads │
└───────────────────────────────┘
A single K3s server is already a complete Kubernetes cluster and can run workloads without separate worker nodes. (K3s Documentation)
Recommended Production Architecture
For production, use 3 server nodes with embedded etcd:
Applications
│
▼
Kubernetes Services
│
Kubernetes API
:6443
│
▼
┌───────────────────┐
│ Fixed API Address │
│ / Load Balancer │
│ 10.10.10.20 │
└─────────┬─────────┘
│
┌──────────────┼──────────────┐
│ │ │
▼ ▼ ▼
┌────────────┐ ┌────────────┐ ┌────────────┐
│ k3s-01 │ │ k3s-02 │ │ k3s-03 │
│10.10.10.21 │ │10.10.10.22 │ │10.10.10.23 │
│ │ │ │ │ │
│ control │ │ control │ │ control │
│ etcd │ │ etcd │ │ etcd │
└──────┬─────┘ └──────┬─────┘ └──────┬─────┘
│ │ │
└───────────────┼───────────────┘
│
Embedded etcd
TCP 2379 / 2380
Optional worker nodes:
┌────────────┐
│ worker-01 │
│10.10.10.31 │
└────────────┘
┌────────────┐
│ worker-02 │
│10.10.10.32 │
└────────────┘
An HA K3s cluster with embedded etcd requires three or more server nodes, and an odd number of servers is recommended to maintain etcd quorum. (K3s Documentation)
System Requirements
K3s officially lists these minimum requirements: (K3s Documentation)
| Node | CPU | RAM |
|---|---|---|
| Server | 2 cores | 2 GB |
| Agent | 1 core | 512 MB |
For a normal production environment, a more practical starting point is:
K3s Server
CPU: 4 vCPU+
RAM: 8 GB+
Disk: 50 GB+ SSD
Worker
CPU: 2-4 vCPU+
RAM: 4-8 GB+
Disk: 40 GB+ SSD
K3s recommends SSD-backed storage because cluster performance depends heavily on datastore performance, particularly with embedded etcd. (K3s Documentation)
Example Cluster
This guide uses:
| Node | Hostname | IP | Role |
|---|---|---|---|
| Server 1 | k3s-01 |
10.10.10.21 |
Control Plane + etcd |
| Server 2 | k3s-02 |
10.10.10.22 |
Control Plane + etcd |
| Server 3 | k3s-03 |
10.10.10.23 |
Control Plane + etcd |
| Worker 1 | k3s-worker-01 |
10.10.10.31 |
Agent |
| Worker 2 | k3s-worker-02 |
10.10.10.32 |
Agent |
Optional fixed cluster API address:
10.10.10.20
Required Ports
For the default K3s networking configuration: (K3s Documentation)
| Protocol | Port | Source | Destination | Purpose |
|---|---|---|---|---|
| TCP | 6443 |
All nodes | Servers | Kubernetes API / K3s supervisor |
| TCP | 2379-2380 |
Servers | Servers | Embedded etcd |
| UDP | 8472 |
All nodes | All nodes | Flannel VXLAN |
| TCP | 10250 |
All nodes | All nodes | Kubelet API / metrics |
If Flannel WireGuard is used instead of VXLAN:
51820/UDP
and for IPv6:
51821/UDP
are required instead. (K3s Documentation)
Do not expose UDP
8472to the public Internet. K3s explicitly warns that doing so exposes the cluster overlay network. (K3s Documentation)
1. Prepare Debian 13
Run on every node:
sudo apt update
sudo apt upgrade -y
Install basic tools:
sudo apt install -y \
curl \
ca-certificates
Check OS:
cat /etc/os-release
2. Configure Hostnames
Node 1:
sudo hostnamectl set-hostname k3s-01
Node 2:
sudo hostnamectl set-hostname k3s-02
Node 3:
sudo hostnamectl set-hostname k3s-03
Worker 1:
sudo hostnamectl set-hostname k3s-worker-01
Worker 2:
sudo hostnamectl set-hostname k3s-worker-02
K3s requires every machine to have a unique hostname, unless a unique K3S_NODE_NAME is explicitly supplied during installation. (K3s Documentation)
3. Configure DNS or /etc/hosts
If internal DNS is unavailable:
sudo nano /etc/hosts
Add on every node:
10.10.10.21 k3s-01
10.10.10.22 k3s-02
10.10.10.23 k3s-03
10.10.10.31 k3s-worker-01
10.10.10.32 k3s-worker-02
Verify:
getent hosts k3s-01
getent hosts k3s-02
getent hosts k3s-03
Single-Node Installation
For development or a small installation:
curl -sfL https://get.k3s.io | sh -
This is the official K3s quick-install command. (K3s Documentation)
The installer automatically:
Installs K3s
Installs kubectl
Installs crictl
Installs ctr
Creates systemd service
Creates kubeconfig
Configures automatic restart
The kubeconfig is created at:
/etc/rancher/k3s/k3s.yaml
Verify Single Node
sudo k3s kubectl get nodes
or simply:
sudo kubectl get nodes
Check pods:
sudo kubectl get pods -A
Check service:
sudo systemctl status k3s
High Availability Cluster
For production, initialize the first server using embedded etcd.
K3s automatically uses embedded etcd when a cluster is initialized using:
--cluster-init
4. Generate Cluster Token
You can create your own strong cluster token:
openssl rand -hex 32
Example:
ab76ea3b589bb0275a...
Save it securely.
For the examples below:
K3S_TOKEN=YOUR_LONG_RANDOM_CLUSTER_TOKEN
All server nodes must use the same token. (K3s Documentation)
5. Install First Server
On:
k3s-01
10.10.10.21
run:
curl -sfL https://get.k3s.io | \
K3S_TOKEN='YOUR_LONG_RANDOM_CLUSTER_TOKEN' \
sh -s - server \
--cluster-init
This initializes the embedded etcd cluster. (K3s Documentation)
Check:
sudo kubectl get nodes
Initially:
NAME STATUS ROLES
k3s-01 Ready control-plane,etcd,master
Fixed Registration / API Address
For an HA cluster, a fixed address is preferable:
k3s.example.local
or:
10.10.10.20
This could be provided by:
HAProxy
Nginx TCP proxy
Keepalived VIP
Cloud Load Balancer
MetalLB-style infrastructure
K3s documents a fixed registration address as an optional component of HA deployments. (K3s Documentation)
Install First Server with Fixed API Address
If:
k3s.example.local → 10.10.10.20
run:
curl -sfL https://get.k3s.io | \
K3S_TOKEN='YOUR_LONG_RANDOM_CLUSTER_TOKEN' \
sh -s - server \
--cluster-init \
--tls-san=k3s.example.local \
--tls-san=10.10.10.20
--tls-san adds the fixed registration address to the Kubernetes API certificate and is appropriate when clients or nodes connect through that address. (K3s Documentation)
6. Join Server 2
On:
k3s-02
10.10.10.22
run:
curl -sfL https://get.k3s.io | \
K3S_TOKEN='YOUR_LONG_RANDOM_CLUSTER_TOKEN' \
sh -s - server \
--server https://10.10.10.21:6443
If using the fixed address:
curl -sfL https://get.k3s.io | \
K3S_TOKEN='YOUR_LONG_RANDOM_CLUSTER_TOKEN' \
sh -s - server \
--server https://k3s.example.local:6443 \
--tls-san=k3s.example.local \
--tls-san=10.10.10.20
K3s documents joining additional HA servers using the shared token and --server address. (K3s Documentation)
7. Join Server 3
On:
k3s-03
10.10.10.23
run:
curl -sfL https://get.k3s.io | \
K3S_TOKEN='YOUR_LONG_RANDOM_CLUSTER_TOKEN' \
sh -s - server \
--server https://10.10.10.21:6443
Or through the fixed address:
curl -sfL https://get.k3s.io | \
K3S_TOKEN='YOUR_LONG_RANDOM_CLUSTER_TOKEN' \
sh -s - server \
--server https://k3s.example.local:6443 \
--tls-san=k3s.example.local \
--tls-san=10.10.10.20
8. Verify HA Cluster
On any server:
sudo kubectl get nodes
Expected:
NAME STATUS ROLES AGE
k3s-01 Ready control-plane,etcd,master
k3s-02 Ready control-plane,etcd,master
k3s-03 Ready control-plane,etcd,master
This matches the HA embedded-etcd topology documented by K3s. (K3s Documentation)
Check detailed status:
sudo kubectl get nodes -o wide
Why 3 Servers?
Embedded etcd uses quorum.
For:
3 servers
quorum is:
2
Therefore:
3 healthy
↓
1 server fails
↓
2 remain
↓
Cluster retains quorum
With only:
2 servers
a single failure leaves only one member, which cannot maintain majority quorum.
K3s therefore requires an odd number of server nodes for a normal embedded-etcd HA topology. (K3s Documentation)
9. Get Node Token
K3s automatically stores the node join token on server nodes at:
/var/lib/rancher/k3s/server/node-token
Read it:
sudo cat /var/lib/rancher/k3s/server/node-token
You can use this instead of supplying your own token manually.
10. Add Worker Node
On:
k3s-worker-01
run:
curl -sfL https://get.k3s.io | \
K3S_URL=https://10.10.10.21:6443 \
K3S_TOKEN='YOUR_CLUSTER_TOKEN' \
sh -
Setting K3S_URL causes the installer to configure the node as a K3s agent rather than a server. (K3s Documentation)
With a fixed address:
curl -sfL https://get.k3s.io | \
K3S_URL=https://k3s.example.local:6443 \
K3S_TOKEN='YOUR_CLUSTER_TOKEN' \
sh -
Add Additional Worker
On:
k3s-worker-02
run:
curl -sfL https://get.k3s.io | \
K3S_URL=https://k3s.example.local:6443 \
K3S_TOKEN='YOUR_CLUSTER_TOKEN' \
sh -
Verify Workers
sudo kubectl get nodes
Expected:
NAME STATUS ROLES
k3s-01 Ready control-plane,etcd,master
k3s-02 Ready control-plane,etcd,master
k3s-03 Ready control-plane,etcd,master
k3s-worker-01 Ready <none>
k3s-worker-02 Ready <none>
Firewall
K3s recommends disabling UFW unless you intentionally configure all necessary cluster rules. If UFW remains enabled, the Kubernetes API, pod network, service network, and any additional cluster ports must be allowed. (K3s Documentation)
UFW — Kubernetes API
On server nodes:
sudo ufw allow 6443/tcp
Prefer restricting this to the cluster network.
Example:
sudo ufw allow \
from 10.10.10.0/24 \
to any port 6443 \
proto tcp
UFW — Embedded etcd
Allow between server nodes only:
sudo ufw allow \
from 10.10.10.0/24 \
to any port 2379:2380 \
proto tcp
K3s requires TCP 2379-2380 between server nodes when embedded etcd HA is used. (K3s Documentation)
UFW — Flannel VXLAN
Allow between cluster nodes:
sudo ufw allow \
from 10.10.10.0/24 \
to any port 8472 \
proto udp
Never allow:
0.0.0.0/0 → UDP 8472
because K3s warns that exposing VXLAN publicly can expose the cluster network. (K3s Documentation)
UFW — Kubelet
sudo ufw allow \
from 10.10.10.0/24 \
to any port 10250 \
proto tcp
K3s requires node-to-node access to 10250/TCP when the metrics server and kubelet APIs are used. (K3s Documentation)
Pod and Service Networks
Default K3s networks include:
Pod CIDR:
10.42.0.0/16
Service CIDR:
10.43.0.0/16
If UFW remains enabled, K3s documentation recommends allowing traffic from these networks: (K3s Documentation)
sudo ufw allow from 10.42.0.0/16
sudo ufw allow from 10.43.0.0/16
Kubeconfig
K3s creates the admin kubeconfig at:
/etc/rancher/k3s/k3s.yaml
Check:
sudo cat /etc/rancher/k3s/k3s.yaml
Use kubectl Without sudo
Create:
mkdir -p ~/.kube
Copy:
sudo cp \
/etc/rancher/k3s/k3s.yaml \
~/.kube/config
Change ownership:
sudo chown \
$USER:$USER \
~/.kube/config
Protect:
chmod 600 ~/.kube/config
Then:
kubectl get nodes
Access Cluster from Another Computer
Copy:
/etc/rancher/k3s/k3s.yaml
to your workstation:
~/.kube/config
The generated kubeconfig normally points to:
https://127.0.0.1:6443
Change it to the fixed API address:
server: https://k3s.example.local:6443
or:
server: https://10.10.10.20:6443
Make sure that address was included as a TLS SAN during server installation.
K3s Configuration File
Instead of putting many options on the install command, K3s can use:
/etc/rancher/k3s/config.yaml
This is useful for production servers.
Example first server:
token: "YOUR_LONG_RANDOM_CLUSTER_TOKEN"
cluster-init: true
tls-san:
- "k3s.example.local"
- "10.10.10.20"
Then install:
curl -sfL https://get.k3s.io | sh -
Server 2 / Server 3 Config
token: "YOUR_LONG_RANDOM_CLUSTER_TOKEN"
server: "https://k3s.example.local:6443"
tls-san:
- "k3s.example.local"
- "10.10.10.20"
Then:
curl -sfL https://get.k3s.io | sh -
K3s supports configuration through install-script options, environment variables, or persisted configuration. (K3s Documentation)
Important: Server Configuration Must Match
Several critical server options must be consistent across HA server nodes, including network CIDRs and component-disable settings. K3s specifically calls out settings such as cluster-cidr, service-cidr, cluster-dns, cluster-domain, and several feature/component flags. (K3s Documentation)
For example, don't configure:
cluster-cidr: 10.42.0.0/16
on one server and:
cluster-cidr: 10.50.0.0/16
on another.
Disable Scheduling on Control Plane Nodes
By default, K3s server nodes can also run workloads.
If you want:
Control Plane:
k3s-01
k3s-02
k3s-03
Workers:
k3s-worker-01
k3s-worker-02
taint the server nodes.
Example:
kubectl taint nodes \
k3s-01 \
node-role.kubernetes.io/control-plane=true:NoSchedule
Repeat:
kubectl taint nodes \
k3s-02 \
node-role.kubernetes.io/control-plane=true:NoSchedule
kubectl taint nodes \
k3s-03 \
node-role.kubernetes.io/control-plane=true:NoSchedule
Then application workloads will normally schedule to worker nodes instead.
Verify Cluster
Nodes:
kubectl get nodes -o wide
Pods:
kubectl get pods -A
Services:
kubectl get svc -A
Deployments:
kubectl get deployments -A
Storage classes:
kubectl get storageclass
Check System Pods
kubectl get pods -n kube-system
Typical K3s components include:
coredns
metrics-server
local-path-provisioner
traefik
svclb
depending on the enabled K3s components.
Check Cluster Version
k3s --version
Kubernetes:
kubectl version
Nodes:
kubectl get nodes
Test Deployment
Create an nginx deployment:
kubectl create deployment nginx \
--image=nginx:alpine
Check:
kubectl get pods
Expose:
kubectl expose deployment nginx \
--port=80 \
--type=ClusterIP
Check:
kubectl get svc
Delete test:
kubectl delete deployment nginx
kubectl delete service nginx
Service Management
K3s Server
Status:
sudo systemctl status k3s
Restart:
sudo systemctl restart k3s
Stop:
sudo systemctl stop k3s
Start:
sudo systemctl start k3s
Logs:
sudo journalctl -u k3s
Follow:
sudo journalctl -u k3s -f
K3s Agent
Status:
sudo systemctl status k3s-agent
Restart:
sudo systemctl restart k3s-agent
Logs:
sudo journalctl -u k3s-agent -f
Container Runtime
K3s includes and uses containerd, so Docker is not required for a standard K3s installation. The K3s install script also installs the ctr and crictl utilities. (K3s Documentation)
Check containers:
sudo k3s crictl ps
Images:
sudo k3s crictl images
Containerd namespaces:
sudo k3s ctr namespaces list
Kubernetes containers:
sudo k3s ctr \
--namespace k8s.io \
containers list
Docker Requirement
Docker is not required for K3s.
K3s already includes its own container runtime.
Only install Docker if you independently need it for:
Building images
Docker Compose workloads
Development tooling
Other non-Kubernetes containers
If Docker is needed, follow:
Quick install:
curl -fsSL https://get.docker.com | sudo sh
Default Storage
K3s includes the Local Path Provisioner by default.
Check:
kubectl get storageclass
For production clustered storage, consider an external/distributed storage system appropriate for your environment rather than relying entirely on node-local volumes.
Embedded etcd Backup
For an HA embedded-etcd cluster, snapshots are an important part of disaster recovery.
Check snapshots:
sudo k3s etcd-snapshot ls
Create snapshot:
sudo k3s etcd-snapshot save
Example:
sudo k3s etcd-snapshot save \
--name manual-backup
Backups should ultimately be copied to storage outside the K3s servers.
Data Directory
K3s data is primarily stored beneath:
/var/lib/rancher/k3s
Configuration:
/etc/rancher/k3s
Kubeconfig:
/etc/rancher/k3s/k3s.yaml
Recommended Backup Architecture
K3s Cluster
│
│ etcd snapshots
▼
Local Snapshot
│
▼
Remote Backup
│
├── S3
├── NAS
└── Backup Server
Fixed API Address with HAProxy
A typical HA deployment should avoid having agents depend on a single server address:
https://10.10.10.21:6443
Prefer:
https://k3s.example.local:6443
Architecture:
k3s.example.local
│
▼
HAProxy
│
┌─────────────┼─────────────┐
▼ ▼ ▼
k3s-01 k3s-02 k3s-03
6443 6443 6443
K3s provides official examples using external Nginx or HAProxy load balancers in front of an HA server cluster. (K3s Documentation)
Check etcd Members
For embedded etcd:
sudo k3s etcd-snapshot ls
K3s embeds etcd directly inside the K3s server process rather than running it as a separate etcd systemd service. (K3s Documentation)
Node Labels
Add a label:
kubectl label node \
k3s-worker-01 \
workload=application
Check:
kubectl get nodes --show-labels
Example deployment selector:
nodeSelector:
workload: application
Drain Node for Maintenance
Before restarting or maintaining a worker:
kubectl drain \
k3s-worker-01 \
--ignore-daemonsets \
--delete-emptydir-data
After maintenance:
kubectl uncordon k3s-worker-01
Remove Worker Node
Drain:
kubectl drain \
k3s-worker-01 \
--ignore-daemonsets \
--delete-emptydir-data
Delete:
kubectl delete node k3s-worker-01
Then on the worker:
sudo /usr/local/bin/k3s-agent-uninstall.sh
Uninstall K3s Server
The official installer places an uninstall script on server nodes. (K3s Documentation)
Run:
sudo /usr/local/bin/k3s-uninstall.sh
This removes the local K3s installation and local cluster state from that server. Do not run it casually on an HA server without considering etcd quorum.
Uninstall Agent
sudo /usr/local/bin/k3s-agent-uninstall.sh
Kill K3s Without Uninstalling
The installer also provides:
k3s-killall.sh
Run:
sudo /usr/local/bin/k3s-killall.sh
This stops K3s containers and cleans runtime state without performing the same full uninstall as k3s-uninstall.sh.
Recommended Production Layout
Users / CI/CD
│
▼
Kubernetes API
│
▼
k3s.example.local
:6443
│
HAProxy / VIP
│
┌────────────────┼────────────────┐
│ │ │
▼ ▼ ▼
k3s-01 k3s-02 k3s-03
control+etcd control+etcd control+etcd
│ │ │
└────────────────┼────────────────┘
│
etcd quorum
│
┌────────────────┼────────────────┐
│ │ │
▼ ▼ ▼
worker-01 worker-02 worker-03
For HA embedded etcd, all server nodes should be able to communicate reliably over their private network; K3s warns against using embedded etcd across distributed/high-latency server locations. (K3s Documentation)
Quick Single-Node Install
curl -sfL https://get.k3s.io | sh -
Verify:
sudo kubectl get nodes
sudo kubectl get pods -A
Quick 3-Node HA Install
Generate token:
openssl rand -hex 32
Assume:
TOKEN=YOUR_CLUSTER_TOKEN
Server 1
curl -sfL https://get.k3s.io | \
K3S_TOKEN='YOUR_CLUSTER_TOKEN' \
sh -s - server \
--cluster-init \
--tls-san=k3s.example.local \
--tls-san=10.10.10.20
Server 2
curl -sfL https://get.k3s.io | \
K3S_TOKEN='YOUR_CLUSTER_TOKEN' \
sh -s - server \
--server https://k3s.example.local:6443 \
--tls-san=k3s.example.local \
--tls-san=10.10.10.20
Server 3
curl -sfL https://get.k3s.io | \
K3S_TOKEN='YOUR_CLUSTER_TOKEN' \
sh -s - server \
--server https://k3s.example.local:6443 \
--tls-san=k3s.example.local \
--tls-san=10.10.10.20
Verify:
sudo kubectl get nodes
Expected:
k3s-01 Ready control-plane,etcd,master
k3s-02 Ready control-plane,etcd,master
k3s-03 Ready control-plane,etcd,master
This is the standard K3s embedded-etcd HA installation pattern. (K3s Documentation)
Quick Worker Install
curl -sfL https://get.k3s.io | \
K3S_URL=https://k3s.example.local:6443 \
K3S_TOKEN='YOUR_CLUSTER_TOKEN' \
sh -
Verify:
kubectl get nodes
Recommended Production Checklist
- [ ] Use at least 3 server nodes for HA embedded etcd.
- [ ] Use an odd number of server nodes.
- [ ] Use SSD storage for K3s server nodes.
- [ ] Give every node a unique hostname.
- [ ] Use stable private IPs or internal DNS.
- [ ] Use a fixed API address or load balancer for HA.
- [ ] Include the fixed API hostname/IP using
--tls-san. - [ ] Keep server configuration consistent across all control-plane nodes.
- [ ] Allow TCP
6443only where required. - [ ] Allow TCP
2379-2380between server nodes only. - [ ] Allow UDP
8472only between cluster nodes when using Flannel VXLAN. - [ ] Never expose
8472/UDPpublicly. - [ ] Allow TCP
10250between nodes where required. - [ ] Keep server nodes on a reliable low-latency network.
- [ ] Do not stretch embedded etcd across distant sites.
- [ ] Use workers for application workloads where appropriate.
- [ ] Back up embedded etcd regularly.
- [ ] Store snapshots off-cluster.
- [ ] Drain worker nodes before maintenance.
- [ ] Maintain etcd quorum during control-plane maintenance.
- [ ] Protect
/etc/rancher/k3s/k3s.yaml. - [ ] Protect the cluster node token.
- [ ] Docker is not required because K3s includes containerd.
References
K3s provides the official one-line installer:
curl -sfL https://get.k3s.io | sh -
and automatically installs the K3s service, kubectl, crictl, ctr, kubeconfig, and uninstall utilities. (K3s Documentation)
The official minimum requirements are 2 CPU cores and 2 GB RAM for a server, and 1 CPU core and 512 MB RAM for an agent. K3s recommends SSD storage where possible because datastore performance is important to cluster performance. (K3s Documentation)
A highly available embedded-etcd deployment requires three or more server nodes and should use an odd number of servers to maintain quorum. The first node is initialized using --cluster-init, and subsequent servers join using --server and the shared token. (K3s Documentation)
K3s requires TCP 6443 for the Kubernetes API, TCP 2379-2380 between embedded-etcd servers, UDP 8472 between nodes with the default Flannel VXLAN backend, and TCP 10250 for kubelet/metrics communication. (K3s Documentation)





