Show examples as

Installation

System requirements

Overview

Building a kcore cluster takes two commands per node from your operator workstation. No SSH, no manual config editing, and no interactive prompts.

  1. Create cluster PKI — one-time operation that generates all trust material.
  2. Install each node — kctl node install partitions the disk, deploys NixOS with LUKS encryption, configures mTLS certificates, and reboots the node into a ready state.

Boot the kcore ISO

Download the kcore NixOS ISO and write it to a USB drive. Boot the target machine from it. The live environment starts a node-agent on port 9091 that accepts install commands from kctl. The default root password is kcore.

Step 1 — Create the cluster PKI

On your operator workstation (where kctl is installed), initialise the cluster trust material. This generates a root CA, sub-CA, controller certificate, and kctl client certificate.

kctl create cluster \
  --controller 192.168.40.107:9090 \
  --context my-cluster
# cluster.yaml
kind: Cluster
metadata:
  name: my-cluster
spec:
  controller: 192.168.40.107:9090

Apply: kctl apply -f cluster.yaml

Showing Terraform examples. Provider source is kcorehypervisor/kcore, version 0.5.0.

kcore_cluster writes the trust material to certs_dir. The first node sets bootstrap. Later nodes set join_controller to that node's controller_address.

terraform {
  required_providers {
    kcore = {
      source  = "kcorehypervisor/kcore"
      version = "0.5.0"
    }
  }
}

provider "kcore" {
  controller_address = "192.168.40.107:9090"
  tls_cert_path      = "${path.module}/certs/kctl.crt"
  tls_key_path       = "${path.module}/certs/kctl.key"
  tls_ca_path        = "${path.module}/certs/ca.crt"
}

resource "kcore_cluster" "my_cluster" {
  name       = "my-cluster"
  controller = "192.168.40.107:9090"
  certs_dir  = "${path.module}/certs"
}

This is a one-time operation per cluster. Certificate material is saved under ~/.kcore/certs/ and the mTLS context is written to ~/.kcore/config with all certificate data embedded inline. Every subsequent kctl command and every kctl node install call uses this context automatically.

If you already have a config file from a previous cluster, add --force (CLI) or force: true (YAML) to overwrite the existing certificate files.

Step 2 — Install the first node

With the target machine booted from the ISO, install kcore to disk. Use --run-controller / runController to start a controller on this node.

kctl node install \
  --node 192.168.40.107:9091 \
  --os-disk /dev/sda \
  --run-controller \
  --dc-id DC1 \
  -k
# node-controller.yaml
kind: NodeInstall
metadata:
  name: kvm-node-107
spec:
  node: 192.168.40.107:9091
  osDisk: /dev/sda
  runController: true
  dcId: DC1
  insecure: true

Apply: kctl apply -f node-controller.yaml

resource "kcore_node" "controller" {
  bootstrap      = true
  address        = "192.168.40.107:9091"
  os_disk        = "/dev/sda"
  certs_dir      = kcore_cluster.my_cluster.certs_dir
  run_controller = true
  dc_id          = "DC1"
  insecure       = true
  hostname       = "kvm-node-107"
}

The installer partitions the disk with LUKS encryption (TPM2-sealed when available), deploys NixOS, configures the controller and node-agent services, provisions mTLS certificates, and reboots. After reboot, the controller listens on :9090, the node-agent on :9091, and the dashboard on :8080.

The node registers with its own controller and is auto-approved by default.

Step 3 — Verify the cluster

After the node reboots, kctl connects over mTLS using the context created in step 1. No additional flags needed:

kctl get nodes
data "kcore_nodes" "all" {}

output "node_hostnames" {
  value = [for n in data.kcore_nodes.all.nodes : n.hostname]
}

You should see the node with status ready and approval approved. The dashboard is available at http://<NODE_IP>:8080.

TLS modes

ModeFlagUse case
mTLS (default)noneProduction — mutual certificate verification. Used for all post-install communication.
Insecure-k / --insecureInitial install only — the live ISO node-agent runs without TLS, so -k is required during kctl node install. After reboot all traffic switches to mTLS automatically.

The -k flag is only needed during kctl node install when communicating with the live ISO. After the node is installed and rebooted, all communication uses mTLS. Never use -k with an installed cluster.

What the installer does

Each kctl node install performs the following non-interactively:

  1. Disk wipe — wipes all signatures and partition tables from the target disk.
  2. Partitioning — creates an ESP boot partition and a LUKS-encrypted root partition (TPM2-sealed when a TPM is available, key-file fallback otherwise).
  3. NixOS install — generates a NixOS configuration, installs the OS, and deploys kcore binaries.
  4. Certificate provisioning — copies the cluster CA and sub-CA, generates a host-specific controller certificate (if --run-controller), and requests a node certificate from the controller (for agent-only installs).
  5. Configuration — writes controller.yaml, node-agent.yaml, and dashboard.env with the correct addresses, replication peers, and TLS paths.
  6. Reboot — unmounts all filesystems and reboots into the installed system.

Webhooks

After install, controller.yaml can POST JSON when a node misses heartbeats, a certificate enters the expiry window, or a VM runtime state changes. Delivery is asynchronous and can be signed with HMAC-SHA256.

webhooks:
  enabled: true
  endpoints:
    - name: pager
      url: https://hooks.example/kcore
      secret: replace-me
      events:
        - node.heartbeat.missed
        - cert.expiry.warning
        - vm.state.changed

Scheduler

The same file sets placement headroom. scheduler.cpuOvercommit and scheduler.memoryOvercommit default to 1.0 and must be between 1.0 and 16.0. VM create uses that ceiling together with --label and --anti-affinity. See VM creation.

Next steps