Every HetznerMachineTemplate you wrote before June 2026 has a serverType string that no longer matches the catalog it was written against. Hetzner didn't just reprice — it renamed the product.
On June 15, 2026, alongside a second DRAM-driven repricing, Hetzner replaced hardware-type SKUs (shared-Intel, shared-AMD, dedicated) with generation SKUs: Cloud Regular Performance (CPX Gen2, x86) and Cloud Cost-Optimized (CX Gen3 x86 / CAX Arm64 on Ampere). The identifier now encodes a moving target, not a stable capability.
This post is for teams running a self-hosted PaaS on Cluster API Provider Hetzner (CAPH). We cover what broke, why generation-named SKUs are worse for IaC than the old names, and how to write templates that survive the next catalog shuffle.
What changed in the catalog
| Before (hardware type) | After (generation) | Arch | What it actually is |
|---|---|---|---|
| CPX (shared AMD) | CPX Gen2 | x86-64 | Regular Performance, current-gen AMD EPYC |
| CX (shared Intel/AMD) | CX Gen3 | x86-64 | Cost-Optimized, current-gen x86 |
| — | CAX | Arm64 | Cost-Optimized, Ampere Altra |
Same API field, new allowed values, no alias. server_type: cpx31 that provisioned last month now returns server type not found. The price move is the headline, but the taxonomy move is the breakage.
Pricing delta (June 2026 hike, selected):
- CAX (Arm64) — ~30% hike
- CX Gen3 / CPX Gen2 AMD lines — 113–175% hike on some families
The cheapest way to keep a stateless web tier on Hetzner is now explicitly the Arm64 line — if your build pipeline can produce linux/arm64.
Why generation names break IaC
Old server_type values named a capability: cpx31 = 4 vCPU, 8 GB, shared AMD. New cpx32-gen2 or cax11 names a catalog slot that Hetzner reserves the right to move to new silicon next generation without changing the generation label semantics.
Two consequences for Cluster API:
- Hardcoded strings drift. Every
HetznerMachineTemplate, Terraformhcloud_server, and autoscalerinstanceTypethat pins a literalserver_typeis now a catalog version pin. - Generation != guarantee.
Gen2today is a specific EPYC stepping.Gen2next year may be a different stepping at the same SKU price. Your benchmark from June is not your capacity in December.
Writing templates that survive a reshuffle
Do:
- Pin by workload class, not SKU. Template for
web-tier-arm64→ select smallest CAX that meets yourrequests.cpu/memory, with a comment linking to the catalog docs, not a hardcodedcax11. - Build multi-arch images. If your buildpacks produce
linux/arm64today, the 30% vs 150% price spread is addressable without a rewrite. - Validate SKU at
clusterctltime. A one-linehcloud server-type listin CI fails fast when a generation rolls.
Don't:
- Copy
server_typefrom a blog post. The value is now time-sensitive. - Assume
Gen2means “faster than Gen1.” It means “current catalog slot.”
The PaaS takeaway
A self-hosted PaaS on owned Hetzner hardware still wins on price variance vs. per-second PaaS meters, but the win now depends on treating the catalog as an API with breaking changes. Version your machine templates like you version your Cluster API manifests — because after June 2026, they are.
If you haven't audited your fleet's HetznerMachineTemplate serverType strings since June 15, do it before the next clusterctl move.