Syself Autopilot can run the Kubernetes control plane on Hetzner Robot dedicated servers. This page covers how to configure and run a bare-metal control plane: selecting the hosts, the rollout behavior, high availability, and switching the control plane between cloud and bare metal. ## Before you begin Control-plane hosts must first be registered with Syself Autopilot as `HetznerBareMetalHost` resources and labeled so a selector can pick them. A minimal set of labels is a role and a cluster, for example `role: controlplane` and `cluster: mycluster`. See [Add bare-metal servers](/docs/hetzner/apalla/servers-and-nodes/bare-metal/add-bare-metal-servers) for registering and labeling hosts. This page uses those labels to select the control-plane hosts. ## Run the control plane on bare metal Set `controlPlane.class` to `hetznerbaremetal` and select the hosts through `controlPlaneHostSelectorBareMetal`: ```yaml spec: topology: controlPlane: class: hetznerbaremetal replicas: 3 variables: overrides: - name: controlPlaneHostSelectorBareMetal value: matchLabels: role: controlplane cluster: mycluster ``` Syself Autopilot claims matching hosts, installs Syself Linux, initializes the first control plane, and joins the remaining members. Each replica runs on its own registered host, so for production run at least three replicas and keep at least that many matching hosts available in your inventory. See [High-availability control plane](/docs/hetzner/apalla/clusters/configure/high-availability-control-plane) for guidance on choosing the replica count. ## Select hosts with `matchLabels` `matchLabels` requires every configured label to match: ```yaml variables: overrides: - name: controlPlaneHostSelectorBareMetal value: matchLabels: role: controlplane cluster: mycluster ``` This is the simplest approach when a set of servers belongs to one clearly defined pool. ## Select hosts with `matchExpressions` Use `matchExpressions` when several groups of hosts are eligible: ```yaml variables: overrides: - name: controlPlaneHostSelectorBareMetal value: matchExpressions: - key: role operator: In values: - controlplane-group-1 - controlplane-group-2 ``` This allows Syself Autopilot to claim any available server matching the expression instead of requiring one exact label value. ## The bare-metal rollout window Bare-metal control planes cannot create temporary surge capacity in the way HCloud control planes can. An HCloud control plane normally uses `maxSurge: 1`, allowing the replacement VM to start before the old one is removed. Bare metal uses `maxSurge: 0`: the physical server must first leave the existing Machine, be reprovisioned, and then rejoin using the new Cluster Stack. For a three-node control plane, the lifecycle looks like this: ```mermaid flowchart LR A["3 control-plane nodes healthy"]:::platform --> B["Drain and remove one member"]:::platform B --> C["2 etcd members remain
quorum still available"]:::platform C --> D["Reprovision physical host"]:::platform D --> E["Node rejoins etcd"]:::platform E --> F["3 control-plane nodes healthy"]:::platform ``` During the reprovisioning window, etcd still has two of three members and remains operational, but there is temporarily no additional control-plane failure tolerance. A second member becoming unavailable can remove quorum. Start bare-metal control plane maintenance only when every member is healthy, and allow each replacement to fully rejoin before the rollout proceeds. Reprovisioning in place has one advantage over HCloud. Because the server is hardware the cluster already owns, a bare-metal rollout never stalls waiting for a Hetzner Cloud VM type to become available in the region, which is a delay an HCloud control plane can hit during an upgrade or recovery. ## High availability on physical servers Each control plane replica runs on its own physical `HetznerBareMetalHost`. Unlike HCloud VMs, Robot servers do not require a placement group to keep several control plane replicas off the same hypervisor. ```mermaid flowchart TB A["Physical server A
control-plane-1"]:::platform B["Physical server B
control-plane-2"]:::platform C["Physical server C
control-plane-3"]:::platform Q["etcd quorum"]:::data A --> Q B --> Q C --> Q ``` With three members, losing one physical server still leaves the two members required for etcd quorum. This protects against a single server failure, not against failure of the entire Hetzner location or other shared infrastructure. Regional disaster recovery requires a separate recovery strategy. ## Switch the control plane between cloud and bare metal `controlPlane.class` determines the infrastructure used by control plane Machines: | Value | Control plane | | ------------------ | ------------------------------- | | `hcloud` | Hetzner Cloud VMs | | `hetznerbaremetal` | Hetzner Robot dedicated servers | Changing the class replaces the existing control plane Machines through a rolling migration. The existing VMs are not converted into physical nodes, and physical nodes are not converted into VMs. Before switching to bare metal, register enough destination hosts and verify that the control plane is completely healthy. Avoid combining the migration with a Kubernetes version upgrade, and monitor each replacement until it has fully joined etcd. > [!WARNING] > Changing `controlPlane.class` replaces every control plane Machine. > > With a three-member control plane, one member is unavailable while its replacement is being provisioned. Do not start the migration while another control plane member is already unhealthy. When moving back to HCloud, make sure the destination region has enough capacity for the requested control plane server type before starting the rollout. ## Related - [High-availability control plane](/docs/hetzner/apalla/clusters/configure/high-availability-control-plane) - [Worker-less cluster](/docs/hetzner/apalla/clusters/configure/worker-less-cluster) - [Add bare-metal servers](/docs/hetzner/apalla/servers-and-nodes/bare-metal/add-bare-metal-servers)