Hetzner Cloud

Hetzner Cloud is Teabar’s primary and recommended infrastructure provider. It offers exceptional price-performance, fast provisioning, and reliable infrastructure across European and US locations.

Why Hetzner?

AdvantageDescription
3-5x cheaperSignificantly lower costs than AWS/Azure for equivalent compute
Fast provisioningVMs ready in ~90 seconds
Simple pricingPredictable hourly rates, no hidden costs
EU data residencyGerman and Finnish datacenters
Excellent networkLow latency, high bandwidth included

Configuration

API Token

Create an API token in the Hetzner Cloud Console:

  1. Navigate to your project
  2. Go to Security > API tokens
  3. Click Generate API token
  4. Select Read & Write permissions
  5. Copy the token

Configure in Teabar

teactl org provider set hetzner --token <HCLOUD_TOKEN>

# Set as default provider
teactl org provider default hetzner

Or via environment variable for self-hosted deployments:

export HCLOUD_TOKEN=<your-token>

Locations

LocationCodeRegionUse Case
Falkensteinfsn1GermanyDefault, lowest latency for EU
Nurembergnbg1GermanyAlternative German location
Helsinkihel1FinlandNordic region, EU data residency
AshburnashUS EastUS East Coast users
HillsborohilUS WestUS West Coast users

Specifying Location

In blueprints:

spec:
  infrastructure:
    provider: hetzner
    location: fsn1  # or nbg1, hel1, ash, hil

Or as a parameter:

spec:
  parameters:
    - name: location
      type: string
      default: fsn1
      enum: [fsn1, nbg1, hel1, ash, hil]
      description: Datacenter location

  infrastructure:
    provider: hetzner
    location: "{{ .Parameters.location }}"

Server Types

Shared vCPU (CX Series)

Best for most workloads. Shared CPU with guaranteed baseline.

TypevCPURAMDiskPrice/hrUse Case
cx1112 GB20 GB~$0.005Minimal workloads, agents
cx2124 GB40 GB~$0.010Participant VMs (recommended)
cx3128 GB80 GB~$0.015K8s workers, databases
cx41416 GB160 GB~$0.030K8s control plane, heavy workloads
cx51832 GB240 GB~$0.060Large applications

Dedicated vCPU (CCX Series)

Guaranteed CPU resources for consistent performance.

TypevCPURAMDiskPrice/hrUse Case
ccx1328 GB80 GB~$0.040Performance-critical workloads
ccx23416 GB160 GB~$0.075Demanding applications
ccx33832 GB240 GB~$0.150Heavy compute
ccx431664 GB360 GB~$0.300Enterprise workloads
ccx5332128 GB600 GB~$0.600Maximum performance

ARM64 (CAX Series)

ARM-based servers for compatible workloads.

TypevCPURAMDiskPrice/hrUse Case
cax1124 GB40 GB~$0.006ARM development
cax2148 GB80 GB~$0.012ARM workloads
cax31816 GB160 GB~$0.024Larger ARM workloads
cax411632 GB320 GB~$0.048Heavy ARM compute

Blueprint Examples

Single VM per Participant

apiVersion: teabar.dev/v1
kind: Blueprint
metadata:
  name: linux-fundamentals
spec:
  infrastructure:
    provider: hetzner
    location: fsn1

  resources:
    - name: participant-vm
      type: vm
      spec:
        size: cx21
        image: ubuntu-22.04
        perParticipant: true
        cloudInit: |
          #cloud-config
          users:
            - name: student
              sudo: ALL=(ALL) NOPASSWD:ALL
              shell: /bin/bash
          packages:
            - vim
            - git
            - docker.io

Kubernetes Cluster

apiVersion: teabar.dev/v1
kind: Blueprint
metadata:
  name: k8s-workshop
spec:
  infrastructure:
    provider: hetzner
    location: fsn1

  resources:
    - name: k8s-cluster
      type: cluster
      spec:
        distribution: talos
        version: "1.29"
        controlPlane:
          count: 1
          size: cx41
        workers:
          count: 3
          size: cx31
        cni: cilium
        addons:
          - metrics-server
          - local-path-provisioner

Multi-tier Application

apiVersion: teabar.dev/v1
kind: Blueprint
metadata:
  name: web-app-stack
spec:
  infrastructure:
    provider: hetzner
    location: fsn1

  resources:
    # Shared database
    - name: database
      type: vm
      spec:
        size: cx31
        image: ubuntu-22.04
        cloudInit: |
          #cloud-config
          packages:
            - postgresql
            - postgresql-contrib

    # Per-participant web server
    - name: webserver
      type: vm
      spec:
        size: cx21
        image: ubuntu-22.04
        perParticipant: true
        cloudInit: |
          #cloud-config
          packages:
            - nginx
            - nodejs
            - npm

Networking

Private Networks

Each environment gets an isolated private network:

spec:
  infrastructure:
    provider: hetzner
    location: fsn1
    network:
      cidr: 10.0.0.0/16
      subnets:
        - name: control-plane
          cidr: 10.0.1.0/24
        - name: participants
          cidr: 10.0.10.0/24

Generated Terraform

Teabar generates Hetzner-specific Terraform:

resource "hcloud_network" "environment" {
  name     = "env-abc123-network"
  ip_range = "10.0.0.0/16"

  labels = {
    environment = "env-abc123"
    managed_by  = "teabar"
  }
}

resource "hcloud_network_subnet" "participants" {
  network_id   = hcloud_network.environment.id
  type         = "cloud"
  network_zone = "eu-central"
  ip_range     = "10.0.10.0/24"
}

Firewalls

Default firewall rules are created for each environment:

spec:
  infrastructure:
    firewall:
      ingress:
        - port: 22
          protocol: tcp
          source: 0.0.0.0/0
          description: SSH access
        - port: 80
          protocol: tcp
          source: 0.0.0.0/0
          description: HTTP
        - port: 443
          protocol: tcp
          source: 0.0.0.0/0
          description: HTTPS
      egress:
        - protocol: all
          destination: 0.0.0.0/0
          description: Allow all outbound

Load Balancers

For environments needing traffic distribution:

resources:
  - name: app-lb
    type: loadbalancer
    spec:
      algorithm: round_robin
      targets:
        - resource: webserver
      services:
        - listenPort: 443
          targetPort: 8080
          protocol: https

Storage

Block Volumes

Attach persistent storage to VMs:

resources:
  - name: data-volume
    type: volume
    spec:
      size: 100  # GB
      format: ext4
      mount: /data

  - name: database
    type: vm
    spec:
      size: cx31
      image: ubuntu-22.04
      volumes:
        - data-volume

Volume Lifecycle

Volumes can be configured for different lifecycle behaviors:

resources:
  - name: data-volume
    type: volume
    spec:
      size: 100
      lifecycle:
        deleteWithEnvironment: false  # Preserve on env deletion
        snapshot:
          enabled: true
          schedule: "0 2 * * *"  # Daily at 2 AM

DNS

Teabar can manage DNS records via Hetzner DNS:

resources:
  - name: app-dns
    type: dns
    spec:
      zone: workshop.example.com
      records:
        - name: "@"
          type: A
          value: "{{ .Resources.app-lb.ip }}"
        - name: "www"
          type: CNAME
          value: "@"

Cost Management

Hourly Pricing

Hetzner charges by the hour with no minimum commitment:

ResourcePricing Model
ServersPer hour (prorated to minute)
VolumesPer GB/month
Load BalancersPer hour + traffic
Floating IPsPer month
NetworksFree

Cost Estimation

View estimated costs before launching:

teactl env estimate --blueprint my-workshop --participants 20

Example output:

Resource Breakdown:
  20x cx21 VMs         $0.20/hr   ($144/month)
  1x cx41 Control VM   $0.03/hr   ($22/month)
  20x 20GB Volumes     $0.02/hr   ($14/month)
  1x Load Balancer     $0.01/hr   ($7/month)
  
Total Estimated Cost:
  Hourly:  $0.26
  Daily:   $6.24
  Monthly: $187

Auto-cleanup

Configure automatic resource cleanup:

spec:
  lifecycle:
    ttl: 8h              # Delete after 8 hours
    sleepAfter: 30m      # Sleep after 30 min idle
    wakeOnAccess: true   # Wake when participant connects

Limitations

FeatureLimitation
Managed KubernetesNot available - use Talos or K3s
GPU instancesLimited availability
Regions5 locations (vs 30+ for AWS/Azure)
ComplianceISO 27001, SOC 1 (fewer than hyperscalers)

Troubleshooting

Common Issues

“Server limit exceeded”

Hetzner has default quotas. Request an increase via the Hetzner Console.

“Location not available”

Some server types aren’t available in all locations. Check Hetzner’s server type availability.

“Network zone mismatch”

Ensure your subnet network zone matches your server location:

LocationsNetwork Zone
fsn1, nbg1, hel1eu-central
ash, hilus-east, us-west

View Provisioning Logs

teactl env logs my-workshop --component provisioner

Next Steps

ende