Install k3s on a Single Linux Node
Install k3s on a single Linux node in minutes: covers the curl installer, kubeconfig setup, built-in Traefik ingress, and essential kubectl commands.
Before you start
- ▸Root or passwordless sudo access on the target node
- ▸curl installed (sudo apt install curl / sudo dnf install curl)
- ▸Ports 6443, 80, and 443 available and not blocked by a host firewall
k3s is a lightweight, certified Kubernetes distribution from Rancher that packages everything into a single binary under 100 MB. It strips out legacy drivers, uses containerd as the container runtime, and replaces etcd with SQLite by default — making it a practical choice for home labs, edge nodes, and CI environments where a full kubeadm cluster is overkill. This guide gets you from a bare Linux node to a running cluster with Traefik ingress in about fifteen minutes.
Prerequisites and System Requirements
k3s officially supports x86_64, ARM64, and ARMv7. You need:
- A 64-bit Linux node with at least 512 MB RAM (1 GB recommended)
curlinstalled- Root or passwordless
sudoaccess - Ports 6443 (API server) and 10250 (kubelet) not already in use
Step 1 — Run the Installer
The official installer script handles binary placement, a systemd unit, and kubeconfig generation in one shot. Run it as root or with sudo:
curl -sfL https://get.k3s.io | sh -
The script detects your architecture, downloads the correct binary to /usr/local/bin/k3s, writes /etc/systemd/system/k3s.service, and starts the service. On a fresh node this typically completes in under two minutes, network speed aside.
If you want to pin a specific version — always a good idea in production — set the INSTALL_K3S_VERSION environment variable:
curl -sfL https://get.k3s.io | INSTALL_K3S_VERSION="v1.30.2+k3s1" sh -
Check the k3s releases page for the current stable tag.
Step 2 — Verify the Service
k3s registers itself as a systemd unit. Confirm it started cleanly:
sudo systemctl status k3s
You should see Active: active (running). If it is still initializing, wait 20–30 seconds and check again. For a live stream of startup logs:
sudo journalctl -u k3s -f
Watch for the line Node controller sync successful — that confirms the control plane is ready.
Step 3 — Configure kubectl Access
k3s writes its kubeconfig to /etc/rancher/k3s/k3s.yaml, readable only by root by default. You have two options.
Option A — Use the k3s kubectl wrapper (quickest)
k3s ships its own kubectl alias. No extra configuration needed:
sudo k3s kubectl get nodes
Option B — Use your system kubectl as a non-root user
This is the better long-term setup. Copy the kubeconfig to your home directory and fix the permissions:
mkdir -p ~/.kube
sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
sudo chown $(id -u):$(id -g) ~/.kube/config
chmod 600 ~/.kube/config
The file references 127.0.0.1:6443 as the server address. If you intend to manage this cluster from another machine, replace that address with the node's actual IP or hostname before copying the file off the node.
kubectl get nodes
Expected output (will vary by hostname and k3s version):
# NAME STATUS ROLES AGE VERSION
# mynode Ready control-plane,master 2m v1.30.2+k3s1
Step 4 — Understand What Traefik Gives You
k3s bundles Traefik v2 as its default Ingress controller, deployed automatically into the kube-system namespace. It also installs a ServiceLB (formerly klipper-lb) that binds host ports 80 and 443 directly on the node — no external load balancer required. Verify both are running:
kubectl get pods -n kube-system -l app.kubernetes.io/name=traefik
kubectl get svc -n kube-system traefik
The traefik Service will show EXTERNAL-IP as the node's primary interface IP once ServiceLB is ready. If you see <pending>, wait another minute for ServiceLB to reconcile.
Step 5 — Deploy a Test Application with Ingress
Deploy a minimal nginx workload and expose it through Traefik to prove the full path works.
Create the Deployment and Service
kubectl create deployment demo --image=nginx:alpine --port=80
kubectl expose deployment demo --port=80
Create an Ingress resource
kubectl apply -f - <<'EOF'
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: web
spec:
rules:
- host: demo.example.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: demo
port:
number: 80
EOF
Test it with curl, faking the Host header so you do not need DNS:
curl -H "Host: demo.example.local" http://127.0.0.1/
You should receive the default nginx welcome page HTML. If you get a 404 from Traefik, give the Ingress a few seconds to sync and retry.
Step 6 — Essential Day-One Commands
A short reference for common k3s operations on a single node:
| Task | Command |
|---|---|
| List all pods, all namespaces | kubectl get pods -A |
| Watch pod events in real time | kubectl get events -A --watch |
| Tail container logs | kubectl logs -f deploy/demo |
| Check node resource usage | kubectl top node (metrics-server is built in) |
| Restart k3s service | sudo systemctl restart k3s |
| Stop and uninstall k3s completely | sudo /usr/local/bin/k3s-uninstall.sh |
Firewall Configuration
If the node runs a firewall, open the API server port so external kubectl clients can reach it. The exact command depends on your firewall manager.
ufw (Debian/Ubuntu)
sudo ufw allow 6443/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
firewalld (Fedora/RHEL/Rocky)
sudo firewall-cmd --permanent --add-port=6443/tcp
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
k3s also needs the CNI flannel network to communicate between pods on the same node. Flannel uses UDP 8472 (VXLAN) internally; this matters if you later add worker nodes.
Troubleshooting
- Node stuck in NotReady: Check
sudo journalctl -u k3s --since "5 min ago"for CNI plugin errors. If flannel cannot write to/run/flannel, ensure SELinux is either in permissive mode or thek3sSELinux policy RPM is installed (sudo dnf install k3s-selinuxon Fedora/RHEL). - Port 6443 already in use: Another process (often a stale k3s or a local kubeadm install) is holding the port. Find it with
sudo ss -tlnp | grep 6443and stop the conflicting service before reinstalling. - curl to Ingress returns connection refused: ServiceLB may not have bound the host port yet. Confirm with
sudo ss -tlnp | grep ':80'— you should seek3s serverorcontainerdlisted. If nothing is listening, check thesvclb-traefikpod logs:kubectl logs -n kube-system -l app=svclb-traefik. - Metrics-server pod CrashLooping: On nodes without a properly configured hostname in DNS, metrics-server TLS verification fails. Add
--kubelet-insecure-tlsto the metrics-server deployment args, or set a valid hostname withhostnamectl set-hostname mynodeand restart k3s.
Frequently asked questions
- Is k3s production-ready?
- Yes. k3s is a CNCF Sandbox project and holds full Kubernetes conformance certification. It is used in production at edge sites and in embedded environments. For high-availability production use, run k3s with an external datastore (PostgreSQL or MySQL) and at least three server nodes.
- Can I disable Traefik and use a different Ingress controller?
- Yes. Pass --disable traefik to the install script: curl -sfL https://get.k3s.io | sh -s - --disable traefik. You can then install nginx-ingress or any other controller via Helm.
- How do I add worker nodes to this single-node install?
- Retrieve the node token from /var/lib/rancher/k3s/server/node-token on the server, then run the installer on each worker with K3S_URL and K3S_TOKEN set: curl -sfL https://get.k3s.io | K3S_URL=https://<server-ip>:6443 K3S_TOKEN=<token> sh -
- Does k3s work on Raspberry Pi?
- Yes, k3s supports ARM64 (Pi 4/5) and ARMv7 (Pi 3). On Raspberry Pi OS you must add cgroup_memory=1 cgroup_enable=memory to /boot/cmdline.txt and reboot before installing, otherwise k3s will start but pods will not schedule.
- What is the difference between k3s and k0s or minikube?
- All three are lightweight Kubernetes distributions, but they target slightly different use cases. minikube is for local development only. k0s is similar to k3s in scope but uses a different CNI default and packaging approach. k3s is the most mature of the lightweight options and has the largest edge-deployment community.
Related guides
Configure Prometheus Alertmanager
Configure Prometheus Alertmanager with routing trees, receivers, inhibition rules, grouping, Go templates, and PagerDuty/Slack on-call integrations.
Build an Intranet Server on Linux
Set up a complete small-office intranet on one Linux box: Nginx web server, dnsmasq local DNS, Samba file sharing, and a Wiki.js team wiki.
Build an nftables Firewall Script
Build a complete nftables firewall from scratch: tables, chains, sets, default-deny input policy, service allowlisting, and persistent systemd configuration.
Caddy as a Reverse Proxy
Set up Caddy as a reverse proxy with automatic HTTPS, load balancing, WebSocket passthrough, reusable snippets, and header control — no certbot required.