Skip to main content

Access a cluster through a domain

Inspect 1.36

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 sizes:

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:

		$ 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:

cluster.yamlyaml
		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: cpx41
 
    variables:
      - name: region
        value: nbg1
 
      - name: controlPlaneMachineTypeHcloud
        value: cpx41
 
      - 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:

		$ kubectl apply -f cluster.yaml
	

See for the complete cluster creation flow.

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:

flowchart LR
    D["k8s.example.com"] --> LB["Hetzner Load Balancer"]
    LB --> CP1["control-plane-1"]
    LB --> CP2["control-plane-2"]
    LB --> CP3["control-plane-3"]

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:

		$ 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:

		$ 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  →  <load-balancer IPv4>
AAAA  app.example.com  →  <load-balancer IPv6>
	

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 .

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 .