Hetzner Cloud

This guide covers machine-controller configuration for Hetzner Cloud.

Prerequisites

  • Hetzner Cloud account
  • API token with read/write permissions
  • Kubernetes cluster with machine-controller installed

Create API Token

  1. Log in to Hetzner Cloud Console
  2. Select your project
  3. Go to SecurityAPI Tokens
  4. Click Generate API Token
  5. Give it a name and select Read & Write permissions
  6. Save the token securely

Provider Configuration

Basic Configuration

cloudProviderSpec:
  # API token
  token: "<< HETZNER_API_TOKEN >>"
  
  # Server type
  serverType: "cx21"
  
  # Location
  location: "fsn1"
  
  # Labels
  labels:
    kubernetesCluster: "my-cluster"

Using Secrets

Create a secret:

kubectl create secret generic hcloud-credentials \
  -n kube-system \
  --from-literal=token=<YOUR_HETZNER_API_TOKEN>

Reference in MachineDeployment:

cloudProviderSpec:
  token:
    secretKeyRef:
      name: hcloud-credentials
      key: token

All Configuration Options

cloudProviderSpec:
  # API token (required)
  token: "<< HETZNER_API_TOKEN >>"
  # Can also be set via HCLOUD_TOKEN env var
  
  # Server type (required)
  serverType: "cx21"
  
  # Location (optional, use location OR datacenter)
  location: "fsn1"  # fsn1, nbg1, hel1, ash, hil
  
  # Datacenter (optional, use location OR datacenter)
  # datacenter: "fsn1-dc14"
  
  # Image (optional, auto-selected based on OS)
  # image: "ubuntu-24.04"
  
  # Networks (optional)
  networks:
    - "my-private-network"
    # Can use network name or ID
  
  # Firewalls (optional)
  firewalls:
    - "worker-firewall"
  
  # Placement group (optional, for spreading)
  placementGroup: "workers-pg"
  
  # Labels (for organization)
  labels:
    kubernetesCluster: "my-cluster"
    environment: "production"

Complete MachineDeployment Examples

Basic Ubuntu Workers

apiVersion: cluster.k8s.io/v1alpha1
kind: MachineDeployment
metadata:
  name: hcloud-ubuntu-workers
  namespace: kube-system
spec:
  replicas: 3
  selector:
    matchLabels:
      name: hcloud-ubuntu-workers
  template:
    metadata:
      labels:
        name: hcloud-ubuntu-workers
    spec:
      providerSpec:
        value:
          cloudProvider: "hetzner"
          cloudProviderSpec:
            serverType: "cx21"
            location: "fsn1"
            token:
              secretKeyRef:
                name: hcloud-credentials
                key: token
            labels:
              kubernetesCluster: "my-cluster"
          operatingSystem: "ubuntu"
          operatingSystemSpec:
            distUpgradeOnBoot: false
      versions:
        kubelet: "<YOUR-KUBERNETES-VERSION>"

Workers with Private Network

apiVersion: cluster.k8s.io/v1alpha1
kind: MachineDeployment
metadata:
  name: hcloud-private-workers
  namespace: kube-system
spec:
  replicas: 3
  selector:
    matchLabels:
      name: hcloud-private-workers
  template:
    metadata:
      labels:
        name: hcloud-private-workers
    spec:
      providerSpec:
        value:
          cloudProvider: "hetzner"
          cloudProviderSpec:
            serverType: "cx21"
            location: "fsn1"
            networks:
              - "k8s-private-network"
            token:
              secretKeyRef:
                name: hcloud-credentials
                key: token
            labels:
              kubernetesCluster: "my-cluster"
          operatingSystem: "ubuntu"
      versions:
        kubelet: "<YOUR-KUBERNETES-VERSION>"

High-Performance Workers

apiVersion: cluster.k8s.io/v1alpha1
kind: MachineDeployment
metadata:
  name: hcloud-performance-workers
  namespace: kube-system
spec:
  replicas: 2
  selector:
    matchLabels:
      name: hcloud-performance-workers
  template:
    metadata:
      labels:
        name: hcloud-performance-workers
    spec:
      providerSpec:
        value:
          cloudProvider: "hetzner"
          cloudProviderSpec:
            serverType: "cpx51"  # 16 vCPU, 32 GB RAM
            location: "fsn1"
            token:
              secretKeyRef:
                name: hcloud-credentials
                key: token
            labels:
              kubernetesCluster: "my-cluster"
              workload: "compute-intensive"
          operatingSystem: "ubuntu"
      versions:
        kubelet: "<YOUR-KUBERNETES-VERSION>"

Rocky Linux Workers

apiVersion: cluster.k8s.io/v1alpha1
kind: MachineDeployment
metadata:
  name: hcloud-rocky-workers
  namespace: kube-system
spec:
  replicas: 3
  selector:
    matchLabels:
      name: hcloud-rocky-workers
  template:
    metadata:
      labels:
        name: hcloud-rocky-workers
    spec:
      providerSpec:
        value:
          cloudProvider: "hetzner"
          cloudProviderSpec:
            serverType: "cx21"
            location: "nbg1"
            token:
              secretKeyRef:
                name: hcloud-credentials
                key: token
            labels:
              kubernetesCluster: "my-cluster"
          operatingSystem: "rockylinux"
      versions:
        kubelet: "<YOUR-KUBERNETES-VERSION>"

Server Types

Standard (Shared vCPU)

TypevCPUsRAMDiskNetworkPrice/mo*
cx1112 GB20 GB20 TB~€4
cx2124 GB40 GB20 TB~€6
cx3128 GB80 GB20 TB~€11
cx41416 GB160 GB20 TB~€18
cx51832 GB240 GB20 TB~€33

Dedicated vCPU

TypevCPUsRAMDiskNetworkPrice/mo*
cpx1122 GB40 GB20 TB~€5
cpx2134 GB80 GB20 TB~€9
cpx3148 GB160 GB20 TB~€16
cpx41816 GB240 GB20 TB~€29
cpx511632 GB360 GB20 TB~€53

*Prices are approximate and subject to change.

List available server types:

# Using hcloud CLI
hcloud server-type list

Locations

Available locations:

  • fsn1 - Falkenstein, Germany (Nuremberg region)
  • nbg1 - Nuremberg, Germany
  • hel1 - Helsinki, Finland
  • ash - Ashburn, VA, USA
  • hil - Hillsboro, OR, USA

List locations:

hcloud location list

Private Networks

Create Private Network

# Create network
hcloud network create \
  --name k8s-private-network \
  --ip-range 10.0.0.0/16

# Create subnet
hcloud network add-subnet k8s-private-network \
  --type cloud \
  --network-zone eu-central \
  --ip-range 10.0.1.0/24

Use in MachineDeployment

cloudProviderSpec:
  networks:
    - "k8s-private-network"

Servers with private networks still get a public IPv4/IPv6 address for outbound connectivity.

Firewalls

Create Firewall

# Create firewall
hcloud firewall create --name worker-firewall

# Add rules
hcloud firewall add-rule worker-firewall \
  --direction in \
  --protocol tcp \
  --port 22 \
  --source-ips 0.0.0.0/0 \
  --source-ips ::/0

hcloud firewall add-rule worker-firewall \
  --direction in \
  --protocol tcp \
  --port 10250 \
  --source-ips CONTROL_PLANE_IP/32

Use in MachineDeployment

cloudProviderSpec:
  firewalls:
    - "worker-firewall"

Placement Groups

Placement groups spread servers across different hosts for high availability:

# Create placement group
hcloud placement-group create \
  --name workers-pg \
  --type spread

Use in MachineDeployment:

cloudProviderSpec:
  placementGroup: "workers-pg"

Multi-Location Deployment

Deploy across multiple locations for geo-distribution:

---
apiVersion: cluster.k8s.io/v1alpha1
kind: MachineDeployment
metadata:
  name: workers-fsn1
  namespace: kube-system
spec:
  replicas: 2
  template:
    spec:
      providerSpec:
        value:
          cloudProviderSpec:
            location: "fsn1"
---
apiVersion: cluster.k8s.io/v1alpha1
kind: MachineDeployment
metadata:
  name: workers-nbg1
  namespace: kube-system
spec:
  replicas: 2
  template:
    spec:
      providerSpec:
        value:
          cloudProviderSpec:
            location: "nbg1"

Troubleshooting

Server Creation Fails

# Check machine events
kubectl describe machine <machine-name> -n kube-system

# Common issues:
# - Invalid API token
# - Server type not available in location
# - Rate limit exceeded
# - Quota/limit reached

Check Hetzner Cloud Status

# Using hcloud CLI
hcloud server list

# Check specific server
hcloud server describe <server-id>

Rate Limiting

Hetzner Cloud has API rate limits (3600 requests/hour). If hitting limits:

  1. Reduce machine-controller worker count
  2. Implement retry logic with backoff
  3. Check for unnecessary API calls

Best Practices

  1. Use Private Networks: For secure inter-node communication
  2. Use Dedicated vCPU: For production workloads (cpx series)
  3. Enable Firewalls: Restrict access to necessary ports
  4. Use Placement Groups: For high availability
  5. Multi-Location: Deploy across locations for resilience
  6. Label Resources: Use labels for organization
  7. Monitor Costs: Hetzner is cost-effective but monitor usage
  8. Backup Important Data: Use Hetzner Volumes for persistent data

Hetzner Cloud CLI

Install the CLI for management:

# Install
brew install hcloud  # macOS
# or download from https://github.com/hetznercloud/cli/releases

# Configure
hcloud context create my-project

# List resources
hcloud server list
hcloud network list
hcloud firewall list

Cost Optimization

  1. Right-Size Servers: Start with cx21, scale as needed
  2. Use Shared vCPU: For non-production (cx series)
  3. Delete Unused Servers: Clean up test/dev resources
  4. Use Volumes Wisely: Detach and reuse volumes
  5. Monitor Traffic: Watch for unexpected network usage

Resources