Skip to content

Quickstart

Get a Kubernetes cluster running on Hetzner in about 15 minutes.

Prerequisites

  • A Hetzner Cloud account, and a project API token with Read & Write permission (Hetzner Console → Security → API tokens):

    bash
    export HCLOUD_TOKEN="<your-token>"
  • The lok8s CLI: one self-contained command (installs the pinned toolchain into your project, nothing touches your system):

    bash
    curl -fsSL https://get.lok8s.io | sh -s -- -p kubeone

    Already using b? These two do the same:

    bash
    b env add github.com/kernpilot/lok8s#kubeone
    b install
  • An SSH key pair (Ed25519 recommended)

  • A domain you control: the cluster’s API endpoint and certificate names are derived from it. You set it in step 1; the reference config ships example.com as a placeholder, not a default.

1. Create your cluster config

lo keeps one folder per cluster, named after the cluster’s domain: clusters/<domain>/cluster.lok8s.yaml. Create the folder inside your project and save the file there:

bash
mkdir -p clusters/example.com
# paste the file below into clusters/example.com/cluster.lok8s.yaml
lo use example.com

lo use marks the domain as active, so every later command knows which cluster you mean.

yaml
# clusters/example.com/cluster.lok8s.yaml
apiVersion: cluster.lok8s.dev/v1beta1
kind: KubeOne
metadata:
  name: my-cluster
spec:
  kubernetes:
    version: "v1.35.5"
  cluster:
    # REQUIRED: a domain you control; used for the API endpoint and cert names
    domain: example.com
  provider:
    name: hetzner
    # The machines, in Hetzner's own terms: each `server` entry becomes one
    # `hcloud server create`, and its keys are hcloud flags. The role comes
    # from the lok8s.dev/role label.
    config:
      cluster_name: my-cluster
      sshUser: root
      sshPrivateKey: ~/.ssh/id_ed25519
      sshPublicKey: ~/.ssh/id_ed25519.pub
      ssh-key:
        - name: my-cluster
          public-key-from-file: ~/.ssh/id_ed25519.pub
      network:
        - name: my-cluster
          ip-range: 10.0.0.0/16
          "#subnets":
            - network-zone: eu-central
              type: cloud
              ip-range: 10.0.0.0/24
      server:
        # 1 control plane for dev; add two more for HA
        - name: cp-1
          type: cx33
          image: ubuntu-24.04
          # fsn1, nbg1, or hel1
          location: fsn1
          ssh-key: [0]
          network: 0
          label: lok8s.dev/cluster=my-cluster,lok8s.dev/role=control-plane
        - name: worker-1
          type: cpx31
          image: ubuntu-24.04
          location: fsn1
          ssh-key: [0]
          network: 0
          label: lok8s.dev/cluster=my-cluster,lok8s.dev/role=worker
        - name: worker-2
          type: cpx31
          image: ubuntu-24.04
          location: fsn1
          ssh-key: [0]
          network: 0
          label: lok8s.dev/cluster=my-cluster,lok8s.dev/role=worker

Change domain (and the folder name) to a domain you control before the next step: nothing in this file can guess it for you. The three SSH paths assume a default-named Ed25519 key (~/.ssh/id_ed25519); if yours is named or stored differently, update those too.

2. Provision

bash
lo provision

This creates your control plane and worker nodes on Hetzner Cloud. The kubeconfig is written to .kubeconfig/my-cluster.yaml in your project, named after metadata.name. Your ~/.kube/config is never touched.

Provisioning typically takes 10–15 minutes. Hetzner bills the servers hourly (a small dev setup runs around €0.03/hour), and you can delete everything anytime with lo destroy.

3. Verify

kubectl still points at whatever context it used before, so select the new cluster explicitly; otherwise get nodes answers for your previous one:

bash
export KUBECONFIG=.kubeconfig/my-cluster.yaml
kubectl get nodes

You should see your control plane and worker nodes in Ready state.

4. Register with kubehz (optional)

This step, and only this step, needs a free kubehz account; the prerequisites above are all the cluster itself requires.

Connect your cluster to the kubehz dashboard for read-only health visibility. Registration is outbound-only: kubehz never gets access into your cluster.

bash
lo kubehz register

This announces the cluster with the status Creating. Then claim it at app.kubehz.cloud to prove ownership and link it to your account (register → claim → owned). See Registration for the details and what the dashboard shows.

Next steps

Doc status

AspectDetail
StateLive: matches the shipped CLI flow; provisioning duration is a conservative bound, not yet timed on the quickstart topology
Last reviewed5 September 2026