Every value you can set under `spec.topology.variables` on a Cluster is here, with its type, default, and what it changes. Syself reads these variables and turns them into settings on the Hetzner infrastructure and on the nodes. For how a variable becomes a node file or an API server flag, see [Declarative cluster management](/docs/hetzner/apalla/concepts/foundations/declarative-cluster-management). The cluster template that ships with your cluster stack release declares the variables. ## How to read this - **Required** variables must be set on every cluster. The rest have a default or are optional. - `…Hcloud` variables apply to HCloud (cloud VM) machines. `…BareMetal` variables apply to Hetzner Robot bare-metal machines. A cluster uses one backend per machine pool. - Today a cluster supports amd64 CPUs only and a single Hetzner region. The `controlPlaneMachineArchHcloud` variable enforces the architecture: its only allowed value is `amd64`. - A few variables are kept in the schema but not offered as features, so a new cluster should not set them: `hcloudNetwork` (private networks) and `workerRaidEnabledBareMetal` / `workerRaidLevelBareMetal` (bare-metal RAID). The schema accepts only their disabled value, and the keys remain so existing manifests keep validating. ## Control-plane endpoint and load balancer | Variable | Type | Required | Default | What it sets | | ------------------------- | ------- | -------- | ------- | --------------------------------------------------------------------------------- | | `clusterEndpointHost` | string | no | `""` | The hostname or IP clients use to reach the API server. | | `clusterEndpointPort` | integer | no | `443` | The port clients use to reach the API server. | | `clusterLoadBalancerType` | string | no | `lb11` | The Hetzner load balancer product for the control plane (`lb11`, `lb21`, `lb31`). | | `clusterLoadBalancerName` | string | no | none | A custom name for the control-plane load balancer. | | `region` | string | **yes** | `fsn1` | The Hetzner region for all cluster infrastructure. One region per cluster. | ## Machine type, architecture, and placement | Variable | Type | Required | Default | What it sets | | --------------------------------------- | ---------------- | -------- | ------- | --------------------------------------------------------------------------------------- | | `controlPlaneMachineTypeHcloud` | string | **yes** | `cpx32` | The HCloud server type for control-plane machines. | | `workerMachineTypeHcloud` | string | **yes** | `cpx32` | The HCloud server type for worker machines. | | `controlPlaneMachineArchHcloud` | string | **yes** | `amd64` | Architecture of HCloud control planes. Only `amd64` is supported; ARM is not available. | | `controlPlanePlacementGroupNameHcloud` | string | no | none | HCloud placement group for control-plane machines. | | `workerMachinePlacementGroupNameHcloud` | string | no | none | HCloud placement group for worker machines. | | `hcloudPlacementGroups` | array of objects | no | none | Cluster-level HCloud placement groups (`name`, `type`). | ## HCloud SSH SSH access to HCloud nodes is not configured with a topology variable. The SSH key attached to HCloud nodes is the one named in the `hcloud-ssh-key-name` field of the `hetzner` Secret the cluster references. See [Prepare your Hetzner account](/docs/hetzner/apalla/getting-started/prepare-your-hetzner-account) for how that Secret is created. ## Bare-metal host selection and RAID | Variable | Type | Required | Default | What it sets | | ----------------------------------- | ------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `controlPlaneHostSelectorBareMetal` | object | no | none | `hostSelector` that binds control-plane machines to a `HetznerBareMetalHost`. Subfields: `matchLabels`, `matchExpressions` (`key`, `operator`, `values`). | | `workerHostSelectorBareMetal` | object | no | none | Same, for worker machines. | | `workerRaidEnabledBareMetal` | boolean | no | `false` | Bare-metal RAID is not offered. The schema accepts only `false`, so a `Cluster` that sets it `true` is rejected at admission. The variable key is kept so existing manifests that set it `false` keep validating. Do not add it to new clusters. | | `workerRaidLevelBareMetal` | integer | no | `1` | Has no effect, because RAID is not offered. The key is kept in the schema for compatibility; do not add it to new clusters. | ## API server policy | Variable | Type | Required | Default | What it sets | | ------------------------- | ------ | -------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `oidcIssuerUrl` | string | no | none | The issuer URL of your OIDC identity provider. OIDC (OpenID Connect) is a standard for identity federation. Takes effect only when set. | | `oidcClientID` | string | no | none | The client ID registered with your identity provider. | | `oidcUsernameClaim` | string | no | `sub` | The token claim used as the Kubernetes username. | | `oidcGroupsClaim` | string | no | `groups` | The token claim used for the user's groups. | | `etcdEncryptionSecretRef` | object | no | none | etcd encryption at rest. Subfields: `enabled` (default `false`), `name` (default `etcd-encryption`), `key` (default `config`). When enabled, writes `/etc/kubernetes/encryption-provider.yaml` from the named Secret and adds the API server `encryption-provider-config` flags. | | `kubeGatePolicySecretRef` | object | no | none | Loads a source-IP allow policy for the API server load-balancer path. KubeGate is the per-node gateway in front of the API server. Subfields: `enabled` (default `false`), `name` (default `kubegate-policy`), `key` (default `policy.yaml`). When enabled, it drops load-balancer connections whose source IP is not in the named Secret's `sourceCIDRs` list. See [Restrict API server access](/docs/hetzner/apalla/security/restrict-api-server-access). | ## DNS | Variable | Type | Required | Default | What it sets | | ------------ | ---------------- | -------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `dnsServers` | array of strings | no | `[]` | Per-cluster DNS servers. Renders into `/run/syself/node-config.json` (`dns.servers`), which the provisioner reads to configure the host resolver and the kubelet `resolvConf`. When unset, the node image's default DNS applies. | `dnsServers` sets the DNS resolvers (the servers that answer name lookups) the nodes use. You only set it to point nodes at your own resolvers. When you leave it unset, nodes use the image defaults, `1.1.1.1` and `8.8.8.8`. Pass IPv4 addresses as a list of strings under `spec.topology.variables`: ```yaml spec: topology: variables: - name: dnsServers value: - "10.0.0.53" - "1.1.1.1" ``` The scope is the node. The kubelet's `resolv.conf` (at `/etc/kubernetes/resolv.conf`) is also where the in-cluster CoreDNS forwards external queries. A pod on the default `ClusterFirst` DNS policy asks CoreDNS first, not these resolvers directly: CoreDNS answers cluster-internal names itself and forwards the rest to the resolvers you set here. So `dnsServers` changes the node resolvers and, through CoreDNS, the upstream for external pod queries. It does not change that a `ClusterFirst` pod's first hop is CoreDNS. Set `dnsServers` when the resolvers baked into the node image do not fit, for example when nodes must resolve names against an internal or private resolver. Leave it unset to keep the image defaults. ## IP families There is no `ipFamilies` topology variable today. A cluster's IP family is fixed at IPv4. IPv6 and dual-stack support are planned but not available yet. ## Private networks | Variable | Type | Required | Default | What it controls | | --------------- | ------ | -------- | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `hcloudNetwork` | object | no | `enabled: false` | Private networks are not offered. The schema accepts only `enabled: false`, so a `Cluster` that sets it `true` is rejected at admission. The variable key is kept so existing manifests that set it `false` keep validating. | ## Infrastructure backends and rollout behavior The cluster template supports two infrastructure backends: HCloud (cloud VMs) and Hetzner Robot (bare metal). Each backend handles control-plane nodes and worker nodes separately. | Backend | Rollout strategy | | ------------------------ | ------------------------------------------------------------------------------ | | HCloud control plane | `maxSurge=1`: a new node starts before the old one is removed | | Bare-metal control plane | `maxSurge=0`: the physical host must be released before it is reprovisioned | | HCloud workers | `maxSurge=1, maxUnavailable=0`: new nodes come up before old ones are removed | | Bare-metal workers | `maxSurge=0, maxUnavailable=1`, with a constant hostname across reprovisioning | Both control-plane backends share the same API server, etcd, scheduler, and controller-manager settings. They differ in rollout strategy and in what triggers automatic remediation: a bare-metal control plane is remediated only on `Ready=False`, while the health daemon's own conditions alert a human there instead. ## When variables take effect Most variables take effect on every cluster, always. Some are conditional. | Variable | Condition for taking effect | | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | | `controlPlaneMachineArchHcloud` | Only `amd64` is applied (the only supported architecture today) | | `dnsServers` | Applied only when the variable is set | | `oidcIssuerUrl` | The OIDC API server flags are added only when this is set | | `etcdEncryptionSecretRef.enabled` | The encryption config and API server flags are added only when `enabled: true` | | `kubeGatePolicySecretRef.enabled` | The KubeGate policy is written to the control planes only when `enabled: true` | | `clusterLoadBalancerName` | A custom load balancer name is set only when this is set | | `hcloudPlacementGroups` | Cluster-level placement groups are added only when this is set | | `controlPlanePlacementGroupNameHcloud` / `workerMachinePlacementGroupNameHcloud` | Placement group name is set per node type only when set | | `controlPlaneHostSelectorBareMetal` / `workerHostSelectorBareMetal` | Host selector is applied only when set | All other variables in this reference are applied to every cluster. ## Fixed network settings The pod and service CIDRs are fixed at cluster creation. You don't set them as topology variables; they come from the cluster's network definition. - **Pod CIDR**: default `100.64.0.0/11`. Written to every node at join time. - **Service CIDR**: default `100.96.0.0/16`. Written to every node at join time. These pair with `maxPods: 220` and a per-node subnet that leaves room for that many pod IPs. Both are set once at cluster creation and cannot be changed on a running cluster. ## Related - [Declarative cluster management](/docs/hetzner/apalla/concepts/foundations/declarative-cluster-management): how variables become cluster configuration. - [Configure OIDC](/docs/hetzner/apalla/clusters/configure/configure-oidc): step-by-step guide for the OIDC variables. - [Encrypt etcd](/docs/hetzner/apalla/security/encrypt-etcd): step-by-step guide for `etcdEncryptionSecretRef`. - [Bare-metal control planes](/docs/hetzner/apalla/clusters/configure/fully-bare-metal-cluster): using `controlPlaneHostSelectorBareMetal`. - [Node labels and annotations](/docs/hetzner/apalla/reference/node-labels-and-annotations): labels Syself sets at node provisioning time.