You can give the Kubernetes API server a domain name instead of accessing the cluster through a raw IP address.
For example:
```text
k8s.example.com
```
Syself Autopilot uses that domain as the stable control-plane endpoint, places it in the API server TLS certificate, and configures the control-plane load balancer to serve it.
Application domains are separate from the cluster API endpoint. You can later expose workloads under domains such as `app.example.com` using Kubernetes Services and ingress or gateway resources.
## Before you create the cluster
The API server domain is configured when the cluster is created.
You need:
- A domain you control.
- A Hetzner Cloud Load Balancer in the same Hetzner project.
- A DNS record pointing the domain to that load balancer.
> [!WARNING]
> The API server domain cannot be changed after the cluster has been provisioned.
>
> Choose the endpoint before creating the cluster.
## Step 1: Create the control-plane load balancer
Create a Load Balancer in the Hetzner Cloud Console and give it a recognizable name, for example:
```text
mycluster-controlplane
```
Remove the default service created by Hetzner and note the assigned public IPv4 address.
Syself Autopilot does not create or delete this load balancer. It manages the control-plane targets attached to it.
This means deleting the Kubernetes cluster does not delete the load balancer from your Hetzner project.
### Choose a load balancer type
Hetzner provides several load balancer types:
| Type | Max concurrent connections | Services | Targets | Certificates |
| ------ | -------------------------: | -------: | ------: | -----------: |
| `lb11` | 10,000 | 5 | 25 | 10 |
| `lb21` | 20,000 | 15 | 75 | 25 |
| `lb31` | 40,000 | 30 | 150 | 50 |
For most clusters, `lb11` is sufficient. Choose a larger type when the cluster requires more load balancer capacity.
## Step 2: Create the DNS record
Create an `A` record for the cluster endpoint and point it to the load balancer IPv4 address.
For example:
```text
k8s.example.com → 203.0.113.10
```
The API endpoint uses IPv4 internally, so an `A` record is sufficient for the control-plane domain.
DNS changes may take time to propagate depending on your DNS provider and record TTL.
Check the result with:
```console
$ dig k8s.example.com
```
The returned address should match the IPv4 address of the Hetzner Load Balancer.
## Step 3: Configure the Cluster
Set the endpoint and load balancer variables in `spec.topology.variables`:
```yaml vars persistBlur title="cluster.yaml"
apiVersion: cluster.x-k8s.io/v1beta2
kind: Cluster
metadata:
name: mycluster
namespace: my-organization
spec:
topology:
classRef:
name: hetzner-apalla-1-36-v1
version: v1.36.3
controlPlane:
class: hcloud
replicas: 3
workers:
machineDeployments:
- class: workeramd64hcloud
name: general
replicas: 3
failureDomain: nbg1
variables:
overrides:
- name: workerMachineTypeHcloud
value: cpx42
variables:
- name: region
value: nbg1
- name: controlPlaneMachineTypeHcloud
value: cpx42
- name: clusterEndpointHost
value: "k8s.example.com"
- name: clusterLoadBalancerType
value: "lb11"
- name: clusterLoadBalancerName
value: "mycluster-controlplane"
```
`clusterEndpointHost` defines the hostname clients use to reach the Kubernetes API server.
`clusterLoadBalancerName` tells Syself Autopilot which existing Hetzner Load Balancer should receive the control-plane nodes as targets, while `clusterLoadBalancerType` describes its type.
Apply the Cluster to the management cluster as usual:
```console
$ kubectl apply -f cluster.yaml
```
See [Cluster Configurator](/docs/hetzner/apalla/cluster-configurator) for the complete cluster creation flow.
Fill in your cluster's fields in the Cluster Configurator and export a ready-to-apply manifest — no hand-written YAML required.
## Why the API domain is fixed
The cluster endpoint is more than a DNS convenience.
During cluster bootstrap, Syself Autopilot uses `clusterEndpointHost` as part of the control-plane identity and connectivity configuration. The hostname is also included in the API server TLS certificate so clients can verify that they are connecting to the correct Kubernetes API server.
In simplified form:
```mermaid
flowchart LR
D["k8s.example.com"]:::external --> LB["Hetzner Load Balancer"]:::external
LB --> CP1["control-plane-1"]:::platform
LB --> CP2["control-plane-2"]:::platform
LB --> CP3["control-plane-3"]:::platform
```
Changing the hostname later would require changing the endpoint used throughout the cluster and replacing the associated API server certificate configuration.
Syself Autopilot therefore treats the API domain as a creation-time setting rather than an ordinary mutable cluster variable.
## Verify the endpoint
After the cluster is ready, inspect its kubeconfig:
```console
$ kubectl get secret mycluster-kubeconfig \
-n my-organization \
-o jsonpath='{.data.value}' \
| base64 -d
```
The server field should use your configured hostname:
```yaml
clusters:
- cluster:
server: https://k8s.example.com:443
```
Test access:
```console
$ KUBECONFIG=./mycluster-kubeconfig.yaml kubectl get nodes
```
If the command succeeds and the nodes report `Ready`, DNS, TLS, the load balancer, and the Kubernetes API endpoint are working together.
## Application domains are separate
The cluster API domain is only for Kubernetes management traffic.
Applications normally use their own domains:
```text
k8s.example.com Kubernetes API
app.example.com Application
grafana.example.com Monitoring
api.example.com Public API
```
When you expose an application through a Kubernetes `Service` of type `LoadBalancer`, the Hetzner cloud-controller-manager can provision a separate application load balancer.
Hetzner application load balancers can expose both public IPv4 and IPv6 addresses. You can therefore create both DNS records when appropriate:
```text
A app.example.com →
AAAA app.example.com →
```
The load balancer terminates the public edge connectivity while the cluster itself continues using IPv4 internally.
How HTTP or HTTPS traffic reaches the application after that depends on whether you use a direct Service, an ingress controller, or a gateway.
See [Expose an application](/docs/hetzner/apalla/network/expose/choose-how-to-expose).
## API access and authentication
Giving the API server a domain does not change Kubernetes authentication.
The endpoint still requires valid Kubernetes credentials. For team access, configure OIDC so users authenticate through your organization's identity provider instead of distributing static administrative kubeconfigs.
See [Configure OIDC](/docs/hetzner/apalla/clusters/configure/configure-oidc).
## Related
- [Networking](/docs/hetzner/apalla/concepts/internals/networking)
- [Cluster Configurator](/docs/hetzner/apalla/cluster-configurator)
- [Configure OIDC](/docs/hetzner/apalla/clusters/configure/configure-oidc)
- [Expose an application](/docs/hetzner/apalla/network/expose/choose-how-to-expose)