The script installs K3s, deploys the control plane, and launches a setup wizard. Once done, open your browser at the configured domain.
Before it changes anything, the script checks RAM, disk, ports, network-range clashes, any Kubernetes already there and outbound access, lists every problem at once and stops with the host untouched (the checks are in [operations §1](docs/operations.md#1-supported-hosts)).
> **This repository is currently private**, so the command above returns 404. Use the
> credentialed form instead; the installer itself needs the same token to resolve and
> download the release, so pass it through with `sudo -E`:
*) preflight_fail "this host is $(uname-m); Felis publishes its images for amd64 and arm64 only";;
esac
systemd_is_init \
|| preflight_fail "systemd is not running as init; the installer manages k3s, the proxy and its timers as systemd units"
# k3s refuses to start without the memory controller. Raspberry Pi OS ships it off.
local controllers
controllers="$(cgroup_controllers)"
case" $controllers "in
*" memory "*);;
*) preflight_fail "the memory cgroup controller is off, and k3s will not start without it (on a Raspberry Pi add 'cgroup_memory=1 cgroup_enable=memory' to /boot/firmware/cmdline.txt and reboot)";;
esac
}
preflight_memory(){
local mem_kb
mem_kb="$(mem_total_kb)"
[-n"$mem_kb"]||return 0
if["$mem_kb"-lt"$PREFLIGHT_MIN_RAM_KB"];then
preflight_fail "this host has $((mem_kb /1024)) MiB of RAM; the full stack needs at least $((PREFLIGHT_MIN_RAM_KB /1024)) MiB (a 2 GB host), 4 GB to run players' servers beside it. Felis-nano (FELIS_INSTALL_MODE=nano) fits in far less"
END { for (i = 1; i <= n; i++) { m = order[i]; print m, size[m], used[m], avail[m], need[m] } }')"
while read-r mount size used avail need;do
[-n"$mount"]||continue
if["$avail"-lt"$need"];then
preflight_fail "${mount} has $((avail /1024)) MiB free; this install writes about $((need /1024)) MiB there (k3s under /var/lib/rancher, the image builds under /var/lib/containerd, the database under /var/lib/felis, sources under /opt/felis)"
continue
fi
# k3s's image GC starts collecting at 85% and the kubelet evicts pods below 5% free.
dev="$(awk'{ for (i = 1; i < NF; i++) if ($i == "dev") { print $(i + 1); exit } }'<<<"$line")"
case "$dev" in cni0|flannel.1|flannel-wg|kube-ipvs0) continue ;; esac
len=32
case "$dst" in */*) len="${dst#*/}" ;; esac
for cidr in "$POD_CIDR" "$SERVICE_CIDR"; do
cidr_overlap "$dst" "$cidr" || continue
if [ "$len" -lt "${cidr#*/}" ]; then
warn "preflight: the route ${dst}${dev:+ via ${dev}} covers k3s's ${cidr}; hosts in ${cidr} on that network will be unreachable from here"
else
preflight_fail "the network ${dst}${dev:+ on ${dev}} lies inside k3s's${cidr}; pods and that network would be confused (move the Docker network or LAN, or reinstall k3s with other ranges)"
fi
done
done <<<"$routes"
}
# preflight_hosts prints the hosts this run downloads from, one per line. Package
# mirrors are left out: the package manager names its own.
preflight_hosts() {
printf '%s\n' github.com
if ! bootstrap_from_tui && [ -z "${FELIS_SKIP_FETCH:-}" ] && [ -z "$FELIS_REF_PINNED" ]; then