Skip to main content
Reference material for Hetzner clusters: every configuration parameter, datacenter location, and the details of the infrastructure Ankra provisions.

Cluster Configuration Options

ParameterDefaultDescription
namerequiredUnique cluster name
credential_idrequiredHetzner API credential ID
ssh_key_credential_idsrequiredArray of SSH key credential IDs
ssh_key_credential_idSingle SSH key credential ID (backward compatible, use ssh_key_credential_ids for multiple)
locationrequiredHetzner datacenter location
network_ip_range10.0.0.0/16Private network IP range
subnet_range10.0.1.0/24Subnet range within the network
bastion_server_typecx23Server type for the bastion host
control_plane_count1Number of control plane nodes
control_plane_server_typecx33Server type for control planes
worker_count1Number of worker nodes (legacy, use node_groups instead)
worker_server_typecx33Server type for workers (legacy, use node_groups instead)
node_groupsArray of node group definitions (see Node Groups)
distributionk3sKubernetes distribution
kubernetes_versionlatestKubernetes version (optional)
include_ingressfalseDeploy the ingress stack (ingress-nginx + cert-manager + Let’s Encrypt)
gitops_credential_nameGitHub credential name for GitOps integration
gitops_repositoryGitHub repository for GitOps (e.g., org/repo)
gitops_branchmasterBranch for GitOps pushes

Hetzner Locations

LocationRegion
fsn1Falkenstein, Germany
nbg1Nuremberg, Germany
hel1Helsinki, Finland
ashAshburn, USA
hilHillsboro, USA
sinSingapore

Node Group API

EndpointMethodDescription
/api/v1/clusters/hetzner/{id}/node-groupsGETList all node groups
/api/v1/clusters/hetzner/{id}/node-groupsPOSTAdd a node group
/api/v1/clusters/hetzner/{id}/node-groups/{name}/scalePUTScale a node group
/api/v1/clusters/hetzner/{id}/node-groups/{name}/instance-typePUTUpgrade instance type
/api/v1/clusters/hetzner/{id}/node-groups/{name}/labelsPUTUpdate labels
/api/v1/clusters/hetzner/{id}/node-groups/{name}/taintsPUTUpdate taints
/api/v1/clusters/hetzner/{id}/node-groups/{name}DELETEDelete a node group

SSH Key API

EndpointMethodDescription
/api/v1/clusters/hetzner/{id}/ssh-keysGETList current and available SSH keys
/api/v1/clusters/hetzner/{id}/ssh-keysPUTUpdate SSH keys on the cluster
/api/v1/clusters/hetzner/{id}/access-infoGETGet bastion and control plane IPs

Architecture

A Hetzner cluster provisions the following infrastructure:
ComponentDescription
Bastion HostJump server for secure SSH access to cluster nodes
Private NetworkIsolated network for inter-node communication
Control Plane(s)Kubernetes control plane nodes
Worker(s)Kubernetes worker nodes organized in node groups, each with independent instance types, labels, and taints
SSH KeysDeployed to all servers for access (multiple keys supported)
External Cloud Providerk3s is configured with cloud-provider=external for Hetzner CCM compatibility
All nodes are deployed within a private Hetzner network. The bastion host provides the only external SSH access point.

Automatic Cloud Integration (hcloud Stack)

Ankra automatically deploys a hcloud stack during cluster provisioning. This stack includes:
  1. hcloud namespace — dedicated namespace for Hetzner cloud components
  2. hcloud-token secret — contains your Hetzner API token and network ID, sourced from the credential used to create the cluster
  3. hcloud-cloud-controller-manager — integrates the cluster with Hetzner Cloud APIs (node metadata, load balancers, node lifecycle)
  4. hcloud-csi — provides persistent storage using Hetzner Cloud Volumes
The hcloud stack is deployed automatically after the Ankra Agent is installed. The CCM and CSI charts both depend on the hcloud-token secret, and Ankra ensures the correct dependency order.
You do not need to manually set up the CCM or CSI driver — they are provisioned as part of cluster creation using the same Hetzner API credential you provided.

External Cloud Provider

Hetzner clusters are provisioned with --kubelet-arg=cloud-provider=external and --disable-cloud-controller. This configures k3s to delegate node initialization to the Hetzner Cloud Controller Manager. When nodes first join the cluster, they carry a node.cloudprovider.kubernetes.io/uninitialized taint that prevents workload scheduling. The CCM removes this taint after initializing each node with its Hetzner provider ID, zone labels, and instance metadata. The Ankra Agent tolerates this taint so it can schedule immediately and begin managing the cluster before the CCM is fully running.

Hetzner Cloud Controller Manager (hcloud-ccm)

The Hetzner Cloud Controller Manager is automatically deployed as part of the hcloud stack and provides:
  • Node metadata — automatic zone, region, and instance type labels on nodes
  • Load Balancers — Kubernetes LoadBalancer services backed by Hetzner Cloud Load Balancers
  • Node lifecycle — automatic removal of deleted nodes from the cluster
  • Route management — pod network routes via Hetzner Cloud Networks
The CCM is deployed in the hcloud namespace with 3 replicas and a PodDisruptionBudget. It reads the Hetzner API token from the hcloud-token secret that Ankra creates automatically.

CCM Configuration

The default CCM values configured by Ankra:
replicaCount: 3
env:
  HCLOUD_TOKEN:
    valueFrom:
      secretKeyRef:
        name: hcloud-token
  HCLOUD_NETWORK_ROUTES_ENABLED:
    value: "false"
  HCLOUD_LOAD_BALANCERS_ENABLED:
    value: "true"
  HCLOUD_LOAD_BALANCERS_USE_PRIVATE_IP:
    value: "true"
  HCLOUD_LOAD_BALANCERS_DISABLE_PRIVATE_INGRESS:
    value: "true"
  HCLOUD_LOAD_BALANCERS_LOCATION:
    value: "<your-cluster-location>"
networking:
  enabled: true
  clusterCIDR: "10.0.0.0/16"
  network:
    valueFrom:
      secretKeyRef:
        name: hcloud-token
podDisruptionBudget:
  enabled: true
  minAvailable: 1
To customize the CCM configuration after creation, edit the hcloud-cloud-controller-manager addon in the hcloud stack via the Stack Builder.
The CCM creates Hetzner Cloud Load Balancers when you create Kubernetes Service resources of type LoadBalancer. These Load Balancers are managed by Hetzner Cloud, not by Ankra. Delete LoadBalancer services before terminating the cluster to avoid orphaned resources and unexpected charges.

Hetzner CSI Driver (hcloud-csi)

The Hetzner CSI Driver is automatically deployed as part of the hcloud stack and provides:
  • Dynamic provisioning — create Hetzner Cloud Volumes on demand via PersistentVolumeClaim
  • Volume expansion — resize volumes without downtime
  • Storage classeshcloud-volumes StorageClass available out of the box

CSI Configuration

The default CSI values configured by Ankra:
controller:
  replicaCount: 3
  hcloudToken:
    existingSecret:
      name: hcloud-token
  podDisruptionBudget:
    enabled: true
node:
  hostNetwork: true
  hcloudToken:
    existingSecret:
      name: hcloud-token
      key: token
storageClasses:
  - name: hcloud-volumes
    defaultStorageClass: true
    reclaimPolicy: Retain
Once deployed, create PersistentVolumeClaims with storageClassName: hcloud-volumes:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-data
spec:
  accessModes: [ReadWriteOnce]
  storageClassName: hcloud-volumes
  resources:
    requests:
      storage: 10Gi
The CSI driver creates Hetzner Cloud Volumes when you create PersistentVolumeClaims using the hcloud-volumes StorageClass. These Volumes are managed by Hetzner Cloud, not by Ankra. The default reclaimPolicy is Retain, meaning Hetzner Volumes are not deleted when PVCs are removed. Delete PVCs and their backing Hetzner Volumes before terminating the cluster to avoid orphaned resources and unexpected charges.

Ingress Stack (Optional)

When include_ingress is enabled during cluster creation, Ankra deploys an ingress stack alongside the hcloud stack. The ingress stack includes:
  1. ingress-nginx — NGINX-based Ingress controller with a Hetzner Cloud Load Balancer
  2. cert-manager — automated TLS certificate management
  3. Let’s Encrypt ClusterIssuer — a letsencrypt-prod ClusterIssuer configured for HTTP-01 validation

Ingress Configuration

The ingress-nginx controller is pre-configured with Hetzner Load Balancer annotations:
controller:
  replicaCount: 2
  service:
    annotations:
      load-balancer.hetzner.cloud/location: "<your-cluster-location>"
      load-balancer.hetzner.cloud/use-private-ip: "true"
  podDisruptionBudget:
    enabled: true
    minAvailable: 1
cert-manager is deployed with CRDs enabled and 2 replicas:
crds:
  enabled: true
replicaCount: 2
podDisruptionBudget:
  enabled: true
  minAvailable: 1

Using Ingress with TLS

Once the ingress stack is deployed, create Ingress resources with automatic TLS:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - app.example.com
      secretName: my-app-tls
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: my-app
                port:
                  number: 80
Point your DNS record for app.example.com to the Hetzner Load Balancer IP (created automatically by ingress-nginx). cert-manager will handle the Let’s Encrypt certificate issuance and renewal.