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.
Tip
Why Hetzner?
| Advantage | Description |
|---|---|
| 3-5x cheaper | Significantly lower costs than AWS/Azure for equivalent compute |
| Fast provisioning | VMs ready in ~90 seconds |
| Simple pricing | Predictable hourly rates, no hidden costs |
| EU data residency | German and Finnish datacenters |
| Excellent network | Low latency, high bandwidth included |
Configuration
API Token
Create an API token in the Hetzner Cloud Console:
- Navigate to your project
- Go to Security > API tokens
- Click Generate API token
- Select Read & Write permissions
- 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
| Location | Code | Region | Use Case |
|---|---|---|---|
| Falkenstein | fsn1 | Germany | Default, lowest latency for EU |
| Nuremberg | nbg1 | Germany | Alternative German location |
| Helsinki | hel1 | Finland | Nordic region, EU data residency |
| Ashburn | ash | US East | US East Coast users |
| Hillsboro | hil | US West | US 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.
| Type | vCPU | RAM | Disk | Price/hr | Use Case |
|---|---|---|---|---|---|
cx11 | 1 | 2 GB | 20 GB | ~$0.005 | Minimal workloads, agents |
cx21 | 2 | 4 GB | 40 GB | ~$0.010 | Participant VMs (recommended) |
cx31 | 2 | 8 GB | 80 GB | ~$0.015 | K8s workers, databases |
cx41 | 4 | 16 GB | 160 GB | ~$0.030 | K8s control plane, heavy workloads |
cx51 | 8 | 32 GB | 240 GB | ~$0.060 | Large applications |
Dedicated vCPU (CCX Series)
Guaranteed CPU resources for consistent performance.
| Type | vCPU | RAM | Disk | Price/hr | Use Case |
|---|---|---|---|---|---|
ccx13 | 2 | 8 GB | 80 GB | ~$0.040 | Performance-critical workloads |
ccx23 | 4 | 16 GB | 160 GB | ~$0.075 | Demanding applications |
ccx33 | 8 | 32 GB | 240 GB | ~$0.150 | Heavy compute |
ccx43 | 16 | 64 GB | 360 GB | ~$0.300 | Enterprise workloads |
ccx53 | 32 | 128 GB | 600 GB | ~$0.600 | Maximum performance |
ARM64 (CAX Series)
ARM-based servers for compatible workloads.
| Type | vCPU | RAM | Disk | Price/hr | Use Case |
|---|---|---|---|---|---|
cax11 | 2 | 4 GB | 40 GB | ~$0.006 | ARM development |
cax21 | 4 | 8 GB | 80 GB | ~$0.012 | ARM workloads |
cax31 | 8 | 16 GB | 160 GB | ~$0.024 | Larger ARM workloads |
cax41 | 16 | 32 GB | 320 GB | ~$0.048 | Heavy ARM compute |
Note
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: "@" Note
Cost Management
Hourly Pricing
Hetzner charges by the hour with no minimum commitment:
| Resource | Pricing Model |
|---|---|
| Servers | Per hour (prorated to minute) |
| Volumes | Per GB/month |
| Load Balancers | Per hour + traffic |
| Floating IPs | Per month |
| Networks | Free |
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
| Feature | Limitation |
|---|---|
| Managed Kubernetes | Not available - use Talos or K3s |
| GPU instances | Limited availability |
| Regions | 5 locations (vs 30+ for AWS/Azure) |
| Compliance | ISO 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:
| Locations | Network Zone |
|---|---|
| fsn1, nbg1, hel1 | eu-central |
| ash, hil | us-east, us-west |
View Provisioning Logs
teactl env logs my-workshop --component provisioner