Lightweight Kubernetes
    Multi-Node

    Deploy k3s on a VPS

    Run lightweight Kubernetes (k3s) on RamNode KVM instances — single-node quickstart, multi-node server and agent joins, firewall rules, storage, and ingress.

    Lightweight Kubernetes (k3s) on RamNode KVM instances. Covers single-node and multi-node (1 server + N agents) topologies.

    Assumptions

    • RamNode KVM VPS(es), Ubuntu 24.04 LTS
    • Private networking between nodes if available (check if your RamNode plan/datacenter offers a private VLAN — otherwise use public IPs + firewall rules restricting the k3s ports to node IPs only)
    • At least 1GB RAM per node (2GB+ recommended for anything beyond a toy workload)

    1. Base prep (all nodes)

    shell
    apt update && apt -y upgrade
    apt -y install curl ufw open-iscsi nfs-common
    swapoff -a
    sed -i '/ swap / s/^/#/' /etc/fstab   # k3s/kubelet expects swap off

    Disable/verify no conflicting firewall state yet — configure ufw explicitly per role below.

    2. Single-node quickstart (server acts as its own worker)

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

    Check status:

    shell
    systemctl status k3s
    k3s kubectl get nodes

    Kubeconfig is at /etc/rancher/k3s/k3s.yaml. For a non-root/remote kubectl:

    shell
    mkdir -p ~/.kube
    cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
    sed -i "s/127.0.0.1/$(hostname -I | awk '{print $1}')/" ~/.kube/config
    chmod 600 ~/.kube/config

    Firewall for single-node (only if exposing the API remotely):

    shell
    ufw allow OpenSSH
    ufw allow 6443/tcp        # k8s API
    ufw enable

    3. Multi-node: server setup

    On the first server node:

    shell
    curl -sfL https://get.k3s.io | sh -s - server \
      --write-kubeconfig-mode 644 \
      --tls-san <server-public-ip-or-hostname>

    Grab the node token for joining agents:

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

    Firewall on the server node:

    shell
    ufw allow OpenSSH
    ufw allow 6443/tcp                  # API server
    ufw allow from <agent-ip-1> to any port 8472 proto udp   # flannel VXLAN, repeat per agent
    ufw allow 10250/tcp                 # kubelet metrics
    ufw enable

    If your RamNode nodes share a private network, restrict 8472/udp and 10250/tcp to the private subnet instead of per-IP rules — much less maintenance:

    shell
    ufw allow from 10.0.0.0/24 to any port 8472 proto udp
    ufw allow from 10.0.0.0/24 to any port 10250 proto tcp

    4. Multi-node: agent setup

    On each additional VPS meant to be a worker:

    shell
    curl -sfL https://get.k3s.io | K3S_URL=https://<server-ip>:6443 \
      K3S_TOKEN=<token-from-server> sh -

    Firewall on agents:

    shell
    ufw allow OpenSSH
    ufw allow from <server-ip> to any port 10250 proto tcp
    ufw allow from 10.0.0.0/24 to any port 8472 proto udp
    ufw enable

    Verify from the server:

    shell
    kubectl get nodes -o wide

    5. HA control plane (optional, 3+ server nodes)

    k3s supports embedded etcd for HA. On the first server:

    shell
    curl -sfL https://get.k3s.io | sh -s - server --cluster-init --tls-san <shared-vip-or-lb-hostname>

    On subsequent server nodes:

    shell
    curl -sfL https://get.k3s.io | sh -s - server \
      --server https://<first-server-ip>:6443 \
      --token <token-from-first-server>

    Put a load balancer or DNS round-robin in front of the server IPs for --tls-san. RamNode doesn't provide a managed LB — use keepalived/VRRP across the server nodes if you need a floating VIP, or point clients at all server IPs via a small nginx/haproxy edge node.

    6. Storage note

    k3s ships with local-path-provisioner by default (hostPath-backed, single-node-affinity — fine for small deployments, not for anything needing pod-mobility of PVCs). For real persistent storage across nodes on RamNode VPS instances, options are:

    • Longhorn (needs open-iscsi, already installed above) — good fit for a small multi-node k3s cluster with local disks
    • NFS server on one node + nfs-subdir-external-provisioner — simplest if you already have a beefy storage node

    7. Uninstall (if needed)

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

    Notes

    • k3s replaces iptables-based kube-proxy config and manages its own firewall-adjacent rules for CNI (flannel by default) — don't fight it with overly broad ufw deny rules on the pod CIDR (default 10.42.0.0/16) or service CIDR (10.43.0.0/16).
    • For anything customer-facing, put a proper ingress controller (Traefik ships by default with k3s) behind a reverse proxy/CDN rather than exposing NodePorts directly on RamNode public IPs.