Skip to main content
Version: 1.0.0

Installation Guide

This guide walks you through creating a k3s cluster in an internet-connected environment and deploying the full NuFi stack with the install script included in the NuFi installation package you received.

Installation flow

StepWhat you doWhere
1. PrerequisitesCheck server requirements, install kubectl/HelmMaster node
2. Install the k3s clusterInstall the master node, join worker nodesAll nodes
3. Prepare GPU/NPU nodesInstall drivers and runtime, label nodesAccelerator nodes
4. Install NuFiRun install.shMaster node
5. Verify and accessCheck status, set up DNS, log in to the dashboardMaster node + client PC
At a glance — full command sequence for a single GPU server
# 1. Install k3s (with Traefik disabled)
curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--disable=traefik" sh -
mkdir -p ~/.kube && sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
sudo chown "$USER:$USER" ~/.kube/config && chmod 600 ~/.kube/config
export KUBECONFIG="$HOME/.kube/config"

# 2. Install the NVIDIA driver + Container Toolkit (see step 3),
# then set nvidia as the default k3s runtime
sudo mkdir -p /etc/rancher/k3s
echo 'default-runtime: nvidia' | sudo tee /etc/rancher/k3s/config.yaml
sudo systemctl restart k3s
kubectl label node "$(hostname)" nvidia.com/gpu.present=true

# 3. Install NuFi (after extracting the bundle)
unzip nufi-helm-bundle.zip && cd nufi-helm
./scripts/install.sh \
--base-domain nufi.example.com \
--registry-server registry.dudaji.com \
--registry-username <username> \
--registry-token <token>

See the step-by-step sections below for what each command does and how to verify it.

1. Prerequisites

Server requirements

ItemRequirement
OSUbuntu 22.04 LTS or later (x86_64)
CPU4 cores or more
RAM16GB or more
Disk200GB or more
NetworkAccess to the NuFi image registry
Ports80 (HTTP) and 443 (HTTPS) must be free on the master node
Why ports 80/443

The NuFi ingress gateway binds directly to ports 80/443 on the master (control-plane) node using hostNetwork. This lets you reach NuFi at the master node IP without a LoadBalancer. If you need different ports, see --external-http-port and --external-https-port under Install options.

Install kubectl and Helm

Install kubectl and Helm on the master node. Prefer the latest instructions in the kubectl official docs and Helm official docs.

sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg openssl nfs-common

# Helm
curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

# kubectl
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
rm kubectl

Verify

kubectl version --client
helm version

Prepare the install files

Copy the NuFi installation package (nufi-helm-bundle.zip) you received to the master node and unzip it. The extracted directory is all you need for the installation.

unzip nufi-helm-bundle.zip
cd nufi-helm
nufi-helm/
├── scripts/install.sh # install script
├── scripts/uninstall.sh # uninstall script
├── values/ # default values per chart, Keycloak Realm file (realm-export.json)
└── charts/ # NuFi local charts

If you use a private registry, also prepare the registry server address, username, and token.

2. Install the k3s cluster

2-1. Master node

k3s installs the Traefik ingress controller by default. Traefik occupies ports 80/443 and conflicts with NuFi's Istio ingress gateway, so you must disable Traefik when installing.

curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--disable=traefik" sh -

Copy the kubeconfig so you can use kubectl as a regular user.

mkdir -p ~/.kube
sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
sudo chown "$USER:$USER" ~/.kube/config
chmod 600 ~/.kube/config
export KUBECONFIG="$HOME/.kube/config"

Verify

kubectl get nodes
kubectl get storageclass
ItemExpected
NodeThe master node is Ready
StorageClasslocal-path is shown as (default)
Traefikkubectl -n kube-system get helmchart traefik must return nothing. If it remains, reinstall k3s with --disable=traefik.
Portssudo ss -ltnp shows no process occupying 80/443
Advanced: use Cilium CNI instead of flannel

To use Cilium instead of the default flannel, disable flannel and network policy when installing k3s, then install Cilium. The default k3s Pod CIDR is 10.42.0.0/16.

curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--flannel-backend=none --disable-network-policy --disable=traefik" sh -

export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
cilium install --version 1.19.4 --set=ipam.operator.clusterPoolIPv4PodCIDRList="10.42.0.0/16"
cilium status --wait

See the Cilium k3s installation docs for details.

2-2. Join worker nodes (optional)

Skip this step for a single-server setup.

For GPU worker nodes

We recommend installing the driver and NVIDIA Container Toolkit first (see 3. Prepare GPU/NPU nodes) before joining. Installing after joining also works, but then you need to restart k3s-agent after configuring the runtime.

Check the join token on the master node.

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

Join from the worker node with the master IP and token.

export MASTER_IP=<master node IP>
export NODE_TOKEN=<token from above>

curl -sfL https://get.k3s.io | K3S_URL="https://${MASTER_IP}:6443" K3S_TOKEN="${NODE_TOKEN}" sh -

Verify — on the master node:

kubectl get nodes

The new worker node is joined once it shows Ready. CNI initialization can take 1–2 minutes.

3. Prepare GPU/NPU nodes

Run this on every node with an accelerator. If you have no accelerators, skip this step and pass --nvidia-enabled false when installing NuFi.

3-1. Install the NVIDIA driver

sudo apt-get update
ubuntu-drivers devices # check the recommended version
sudo apt install <driver package marked as recommended>

Verify

nvidia-smi

3-2. Install the NVIDIA Container Toolkit

sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg2

curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey \
| sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg

curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list \
| sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' \
| sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list

sudo apt-get update
sudo apt-get install -y nvidia-container-toolkit

3-3. Set nvidia as the default k3s runtime

Set the default runtime to nvidia so GPU containers can use GPUs without extra configuration.

sudo mkdir -p /etc/rancher/k3s
cat <<'EOF' | sudo tee /etc/rancher/k3s/config.yaml
default-runtime: nvidia
EOF

Restart the k3s service that matches the node role.

# Worker node
sudo systemctl restart k3s-agent

# Master node with a GPU installed
sudo systemctl restart k3s

Verify

sudo grep -n "default_runtime_name\|BinaryName" /var/lib/rancher/k3s/agent/etc/containerd/config.toml

You should see default_runtime_name = "nvidia". If not, delete the containerd config generated by k3s so it is recreated, then restart.

sudo rm -rf /var/lib/rancher/k3s/agent/etc/containerd
sudo systemctl restart k3s-agent # use k3s on the master

3-4. Label GPU nodes

Label the GPU nodes from the master node.

kubectl label node <gpu-node-name> nvidia.com/gpu.present=true

4. Install NuFi

On the master node, move into the bundle directory and run the install script. It is safe to re-run; running the same command again acts as an upgrade.

cd nufi-helm
chmod +x scripts/install.sh

Pick the command that matches your environment.

./scripts/install.sh \
--base-domain nufi.example.com \
--registry-server registry.dudaji.com \
--registry-username <username> \
--registry-token <token>

The NVIDIA device plugin and DCGM exporter are installed together (--nvidia-enabled defaults to true).

Pass only the domain to --base-domain, without a port. After installation you will access NuFi at dashboard.<domain>, api.<domain>, keycloak.<domain>, and grafana.<domain>.

Production passwords

The default NuFi Dashboard login account is admin / nufiadmin. Do not keep the default password in production.

The dashboard NextAuth secret is generated automatically on first install and preserved on later re-runs. Set NEXTAUTH_SECRET only when you need to rotate it.

What gets installed

After preparing namespaces, Secrets, and CRDs, the script installs Helm releases in the following order.

ComponentReleasesRole
Istioistio-base, istiod, istio-gatewayIngress gateway, service routing
Keycloakkeycloak, keycloak-admin-passwordAuthentication/SSO (realm super-llm imported automatically)
Monitoringprometheus, loki, nufi-monitoringMetrics/log collection, Grafana dashboards
AutoscalingkedaServing autoscaling
Storagecsi-driver-nfs, juicefs-minio, juicefs-meta, juicefs-csi, juicefs-configShared volume storage
Devices (optional)nvidia-device-plugin, dcgm-exporter / 3 furiosa-* releasesGPU/NPU resource exposure, metrics
DNScoredns-customIn-cluster *.<domain> routing
Notebooknotebook-controllerLab (Jupyter) controller
NuFi applicationsnufi-controller, nufi-api-server, dashboardNuFi core

Install options

Commonly used options. Run ./scripts/install.sh --help for the full list.

OptionDescriptionDefault
--base-domainBase domain for NuFi services (no port)nufi.local
--registry-server / --registry-username / --registry-tokenPrivate registry credentials. When set, an imagePullSecret is created in every namespace.none
--nufi-versionImage tag for the NuFi applicationsversions.nufi in values/bundled.yaml
--nvidia-enabledWhether to install the NVIDIA device plugin and DCGM exportertrue
--furiosa-enabledWhether to install the Furiosa NPU componentsfalse
--external-http-port / --external-https-portExternal HTTP/HTTPS ports. If changed, include the port in access URLs.80 / 443
--tls-enabledWhether to install the HTTPS gateway and cert-manager. Use only when certificates are prepared.false
--storage-sizeShared storage (JuiceFS) PVC size100Gi
--apps-onlySkip dependency releases and upgrade only the 3 NuFi applicationsfalse
--skip-repo-updateSkip refreshing already-configured Helm repositoriesfalse
If installation is slow or times out

Re-run with a longer timeout, e.g. HELM_TIMEOUT=30m ./scripts/install.sh .... Re-running is always safe.

5. Verify and access

5-1. Check status

helm list -A
kubectl get pods -A

Confirm the Pods in the core namespaces are Running or Completed.

kubectl -n istio-system get pods
kubectl -n keycloak get pods
kubectl -n monitoring get pods
kubectl -n nufi get pods
kubectl -n kubeflow get pods

Confirm GPU/NPU nodes expose their resources.

# NVIDIA
kubectl describe node <gpu-node-name> | grep -i nvidia.com/gpu

# Furiosa
kubectl describe node <npu-node-name> | grep -i furiosa

5-2. Set up DNS

NuFi uses fixed hosts like dashboard.<domain> together with dynamic hosts created per Serving, so dynamic hosts under <domain> must resolve to the master node IP.

EnvironmentMethod
Corporate/production networkRegister wildcard records under <domain> pointing to the master node IP on your internal DNS server
Access from a personal PCFollow the DNS Setup Guide to configure local DNS on the client PC

For quick client-only access setup, use the NuFi-provided nufi-access script.

# macOS/Linux
curl -LsSf https://docs.nufi.me/install/nufi-access.sh | sudo bash -s -- --mode wildcard --base-domain <domain> <master node IP>
# Windows PowerShell
# If Chocolatey is not installed, install it first by following the DNS Setup Guide.
powershell -NoProfile -ExecutionPolicy Bypass -Command "& ([scriptblock]::Create((irm https://docs.nufi.me/install/nufi-access.ps1))) -Mode wildcard -BaseDomain <domain> -NodeIp <master node IP>"

See the DNS Setup Guide for Chocolatey installation and cleanup commands on Windows.

5-3. Access

curl "http://api.<domain>/api/v1/healthz"

Open the dashboard in a browser.

http://dashboard.<domain>
ServiceURLDefault account
Dashboardhttp://dashboard.<domain>admin / nufiadmin

Upgrade and uninstall

Upgrade

Run the same command you used for installation. To move to a new NuFi version, change only --nufi-version. To upgrade just the NuFi applications quickly:

./scripts/install.sh --base-domain <domain> --nufi-version <new version> --apps-only

Uninstall

./scripts/uninstall.sh

This removes the Helm releases in reverse install order. CRDs, PVCs, Secrets, and namespaces are preserved, so data survives a reinstall.

To remove the k3s cluster itself:

# Master node
sudo /usr/local/bin/k3s-uninstall.sh

# Worker node
sudo /usr/local/bin/k3s-agent-uninstall.sh

Troubleshooting

SymptomWhat to check
No default StorageClass foundCheck for a (default) StorageClass with kubectl get sc. The k3s default is local-path.
Keycloak realm export not foundConfirm values/realm-export.json is included in the install bundle.
Cannot access the dashboardConfirm the wildcard DNS resolves to the master node IP and the gateway is Running via kubectl -n istio-system get pods.
Image pull failuresCheck the registry server/username/token, then inspect Events in kubectl -n nufi describe pod <pod>.
NVIDIA resources not visibleCheck nvidia-smi, the runtime setup in 3-3, and the kubectl -n kube-system get ds nvidia-device-plugin status.
Furiosa resources not visibleConfirm furiosa-smi info succeeds on the host and that you installed with --furiosa-enabled true.
Helm install timeoutIncrease the timeout with HELM_TIMEOUT=30m ./scripts/install.sh ..., then inspect slow Pods with kubectl describe pod and kubectl logs.
Worker node never becomes ReadyConfirm the firewall allows worker→master TCP 6443 and UDP 8472 (flannel), and check journalctl -u k3s-agent -f.
Redo a worker node join from scratch (clean up leftovers)

If a join went wrong, clean up the k3s and network leftovers on the worker, then rejoin.

# On the worker node
sudo systemctl stop k3s-agent || true
sudo /usr/local/bin/k3s-agent-uninstall.sh || true

# Clean up leftover network interfaces
sudo ip link delete flannel.1 2>/dev/null || true
sudo ip link delete cni0 2>/dev/null || true
sudo ip link delete kube-ipvs0 2>/dev/null || true

# Clean up k3s/CNI leftovers
sudo rm -rf /etc/rancher/k3s /etc/rancher/node /var/lib/rancher/k3s \
/var/lib/cni /etc/cni/net.d /run/flannel /var/run/flannel

# Reboot to fully clear kernel network state
sudo reboot

If the node still appears on the master, delete it and rejoin.

kubectl delete node <worker-node-name>

Other cluster environments

kind (local validation/CI only)

kind is suitable for local validation and CI smoke tests; it is not a production path.

kind create cluster --name nufi-helm
./scripts/install.sh --base-domain nufi.local --nvidia-enabled false --furiosa-enabled false

install.sh auto-detects kind clusters and applies kind-specific values that disable the gateway's hostNetwork. After installation, access the dashboard via port-forward.

sudo kubectl -n istio-system port-forward svc/istio-ingressgateway 80:80 --address 0.0.0.0

When configuring DNS, use 127.0.0.1 as the NuFi server IP.

Existing Kubernetes cluster

What to check when using an existing cluster:

ItemExpected
kubeconfigkubectl get nodes and kubectl get ns work with admin permissions
Default StorageClassAt least one (default) StorageClass in kubectl get sc
Gateway schedulingPods can be scheduled on a node labeled node-role.kubernetes.io/control-plane=true
External accessPorts 80/443 on the gateway node are reachable from user PCs

Environments like managed Kubernetes — where workloads cannot run on control-plane nodes or hostNetwork port binding is restricted — may not match the default install values. Decide on the gateway exposure method and ports first, then pass --external-http-port and --external-https-port accordingly.

Next steps