This is for Hetzner's dedicated (bare-metal) servers, the ones you manage through Hetzner Robot. Adding one takes two steps. First, register it as a `HetznerBareMetalHost` object, so Syself Autopilot knows the machine exists. Second, add a worker pool (a `machineDeployments` entry) that uses the bare-metal class, so the cluster claims the machine. If you have not bought and prepared the server yet, do [Order and prepare a Robot server](/docs/hetzner/apalla/servers-and-nodes/provision/order-and-prepare-a-robot-server) first. > [!NOTE] > Syself Autopilot manages the software install and the adding and removing of machines from the cluster. It does **not** buy or sell the servers. ## Create one HetznerBareMetalHost per server Create a `baremetalhosts.yaml` with one entry per machine and apply it to the management cluster. Each host needs its Hetzner `serverID` and the `wwn` of the disk to install onto. WWN (World Wide Name) is a unique ID for a disk. ```yaml title="baremetalhosts.yaml" apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 kind: HetznerBareMetalHost metadata: name: baremetal-1 spec: description: My first baremetal machine serverID: 1234567 rootDeviceHints: wwn: eui.726163646f6d2d2d maintenanceMode: false --- apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 kind: HetznerBareMetalHost metadata: name: baremetal-2 spec: description: My second baremetal machine serverID: 7654321 rootDeviceHints: wwn: eui.737472696e677349cd maintenanceMode: false ``` `maintenanceMode` stays `false` for normal operation. Set it `true` only to pause Syself Autopilot's management of this one host, for example while [granting Syself temporary access](/docs/hetzner/apalla/support/grant-syself-baremetal-access) to the physical machine. > [!WARNING] > Newly purchased machines come with RAID enabled by default. Syself Autopilot never supports RAID: it always installs onto a plain disk. If a machine was previously configured with RAID, [wipe the disks](/docs/hetzner/apalla/servers-and-nodes/maintenance/wipe-a-disk) before adding it. If you do not know the `wwn`, boot the server into the Hetzner rescue system (activate it on the **Rescue** tab in the [Robot console](https://robot.hetzner.com/), then reset the server on the **Reset** tab), and read the `wwn-*` symlinks: ```console $ ls -l /dev/disk/by-id/ | grep -E 'wwn|nvme' ``` The WWN column in `lsblk` is often blank in rescue, so `/dev/disk/by-id/` is the reliable source. For the full rescue steps, see [Serial console and rescue system](/docs/hetzner/apalla/servers-and-nodes/access/serial-console-and-rescue). Or omit `rootDeviceHints` entirely: the host stops with an error, and you read the WWN from the inventory it collected: ```console $ kubectl get hbmh -o jsonpath='{.spec.status.hardwareDetails.storage}' | jq ``` On a **multi-disk server**, choose the disk you want the OS installed onto and put its WWN here; the other disks become data disks. Prefer the disk with the least capacity for the OS. It leaves the larger ones free for data storage. On a **single-disk server**, there is only one choice. ## Label hosts and select them from a pool By default, any bare-metal pool can claim any free host. To steer specific machines into a specific cluster or pool, label the host and select it. Add a label to the host: ```yaml title="baremetalhost.yaml" apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 kind: HetznerBareMetalHost metadata: name: baremetal-1 labels: environment: production spec: serverID: 1234567 rootDeviceHints: wwn: eui.726163646f6d2d2d maintenanceMode: false ``` Then add a pool that selects it with `workerHostSelectorBareMetal`, under `spec.topology.workers.machineDeployments`: ```yaml - class: workeramd64baremetal name: md-1 replicas: 1 variables: overrides: - name: workerHostSelectorBareMetal value: matchLabels: environment: production ``` `workerHostSelectorBareMetal` also accepts `matchExpressions` (`key`, `operator`, `values`), for label conditions beyond an exact match. Set the variable once under `spec.topology.variables` to apply it to every bare-metal pool, or override it per pool as shown above. You can run several bare-metal pools in one cluster, each with its own selector. See [Cluster variables](/docs/hetzner/apalla/reference/cluster-variables) for the full field list. > [!TIP] > Always set `matchLabels` (or `matchExpressions`) on bare-metal pools. Without a selector, any available host can be pulled into the pool, including ones you labelled for another purpose. > [!NOTE] > If a pool's selector matches only one host, a failed machine will be reprovisioned on that same host after repair. Reprovisioning fixes software problems, but it cannot fix faulty hardware, so a hardware failure can return after the reinstall. Monitor [node conditions](/docs/hetzner/apalla/servers-and-nodes/access/node-problem-detection-and-conditions) to detect these failures. See [Self-healing does not repair hardware](/docs/hetzner/apalla/servers-and-nodes/maintenance/machine-health-checks-and-remediation#self-healing-does-not-repair-hardware). ## Watch the provision ```console $ kubectl get hbmh -w $ kubectl get machines -o wide -w ``` `-o wide` shows the node name and provider ID next to each machine; bare-metal machines use an `hrobot://` provider ID. The node has joined once the `Machine` reaches the `Running` phase. A bare-metal worker node is ready in a **few minutes**. The machine boots the rescue system, the provisioner writes the sealed OS to the chosen disk, and the node reboots and joins the cluster. > [!NOTE] > If a host stays stuck for a long time, the usual cause is the boot order: the server boots from its own disk instead of the network rescue system. Now and then Hetzner itself has trouble moving a server into rescue mode, which looks the same from the outside. Either way, see [A server that will not provision](/docs/hetzner/apalla/servers-and-nodes/access/server-not-provisioning). The provisioner runs one pipeline inside the rescue system, and stops before the next step if any step fails: - **Preparation**: checks that the target disk exists, is large enough, and passes a quick health and speed check. - **Image deployment**: writes the sealed OS image to the disk, then verifies the written bytes against the build-time hash before trusting them. - **Bootstrap delivery**: stages the files that differ per node, such as the kubeadm config, hostname, and SSH host keys. - **Seal**: stages this node's settings into the sealed OS, verifies them, and writes the boot configuration. - **Handover**: unmounts the disk and reboots into the installed OS. ## What survives a reinstall Only the root disk is reinstalled. **Data on the other disks survives** a reprovision, which is what makes bare metal a good home for stateful workloads. To clear a data disk, wipe it yourself in the rescue system; see [Wipe a disk](/docs/hetzner/apalla/servers-and-nodes/maintenance/wipe-a-disk). > [!NOTE] > Within one pool (one `machineDeployments` entry), bare-metal hosts roll out **one machine at a time**. A change that replaces hosts (an image update, a class change) reprovisions them one after another, so the pool runs with fewer machines available until the rollout finishes. > > This guarantee is per pool. If you split a workload across several pools, it weakens: pools currently roll one after another, but that ordering is not guaranteed to hold in the future. So keep a database's servers within a single pool. A bare-metal pool scales like a cloud pool: change `replicas` and apply. See [Scale a node pool](/docs/hetzner/apalla/servers-and-nodes/pools/scale-a-pool) for what happens on scale-down, or [Remove a specific node](/docs/hetzner/apalla/servers-and-nodes/maintenance/remove-a-specific-node) to take one named machine out instead of letting Syself Autopilot pick. For why dedicated hardware and cloud VMs mix well in the same cluster, see [Bare metal and cloud](/docs/hetzner/apalla/concepts/internals/bare-metal-and-cloud) and [bare-metal Kubernetes](/docs/hetzner/apalla/concepts/internals/bare-metal-and-cloud). ## Related - [Order and prepare a Robot (bare-metal) server](/docs/hetzner/apalla/servers-and-nodes/provision/order-and-prepare-a-robot-server) - [Wipe a disk before provisioning](/docs/hetzner/apalla/servers-and-nodes/maintenance/wipe-a-disk) - [A server that will not provision](/docs/hetzner/apalla/servers-and-nodes/access/server-not-provisioning) - [Remove a specific node](/docs/hetzner/apalla/servers-and-nodes/maintenance/remove-a-specific-node)