Skip to content

Hetzner

Hetzner Cloud provides cost-effective virtual machines and storage in European and US data centres. It's an excellent choice for VM-based deployments where you need more control than managed platforms offer.

Authentication

Set your Hetzner Cloud API token as an environment variable:

bash
export HCLOUD_TOKEN="your-token"

Generate a token at console.hetzner.cloud under your project's Security → API Tokens.

Virtual machines

Hetzner VMs (called "servers") offer excellent price-to-performance ratio for self-managed deployments.

Configuration

json
{
  "apps": [
    {
      "name": "api",
      "type": "golang",
      "path": "./apps/api",
      "infrastructure": {
        "provider": "hetzner",
        "type": "vm",
        "config": {
          "size": "cx22",
          "location": "nbg1",
          "image": "ubuntu-22.04"
        }
      }
    }
  ]
}

Server types

Hetzner offers shared (CX) and dedicated (CCX/CPX) CPU options:

Shared vCPU (CX series)

TypevCPUsMemoryStorageMonthly cost
cx2224GB40GB~€4
cx3248GB80GB~€7
cx42816GB160GB~€14
cx521632GB320GB~€29

Dedicated vCPU (CCX series)

TypevCPUsMemoryStorageMonthly cost
ccx1328GB80GB~€13
ccx23416GB160GB~€25
ccx33832GB240GB~€50
ccx431664GB360GB~€100

ARM64 (CAX series)

TypevCPUsMemoryStorageMonthly cost
cax1124GB40GB~€4
cax2148GB80GB~€6
cax31816GB160GB~€12
cax411632GB320GB~€24

ARM servers offer excellent value for compatible workloads.

Locations

CodeLocationRegion
nbg1NurembergGermany
fsn1FalkensteinGermany
hel1HelsinkiFinland
ashAshburnUSA East
hilHillsboroUSA West

Images

ImageDescription
ubuntu-22.04Ubuntu 22.04 LTS
ubuntu-24.04Ubuntu 24.04 LTS
debian-12Debian 12 (Bookworm)
rocky-9Rocky Linux 9
fedora-40Fedora 40

SSH configuration

WebKit configures SSH access to Hetzner VMs. Ensure your SSH public key is available:

json
{
  "infrastructure": {
    "provider": "hetzner",
    "type": "vm",
    "config": {
      "ssh_keys": ["your-key-name"]
    }
  }
}

SSH keys are managed at the Hetzner project level.

Volumes

Hetzner Volumes provide additional block storage for your VMs.

Configuration

json
{
  "resources": [
    {
      "name": "data",
      "type": "volume",
      "provider": "hetzner",
      "config": {
        "size": 100,
        "location": "nbg1",
        "format": "ext4"
      }
    }
  ]
}

Volume sizes

Volumes range from 10GB to 10TB. Pricing is ~€0.05/GB/month.

SizeMonthly cost
10GB~€0.50
50GB~€2.50
100GB~€5
500GB~€25
1TB~€50

Mount points

Volumes are automatically attached to the associated VM. Configure the mount point:

json
{
  "config": {
    "mount_point": "/data"
  }
}

WebKit configures the VM to mount the volume at boot.

Outputs

OutputDescription
data.idVolume ID
data.sizeVolume size in GB
data.mount_pointMount path on VM

Networking

Private networks

Enable private networking between VMs:

json
{
  "infrastructure": {
    "provider": "hetzner",
    "type": "vm",
    "config": {
      "network": {
        "enabled": true,
        "ip_range": "10.0.0.0/24"
      }
    }
  }
}

VMs in the same network can communicate over private IPs.

Firewalls

Configure firewall rules:

json
{
  "config": {
    "firewall": {
      "rules": [
        {
          "direction": "in",
          "protocol": "tcp",
          "port": "22",
          "source_ips": ["0.0.0.0/0"]
        },
        {
          "direction": "in",
          "protocol": "tcp",
          "port": "80",
          "source_ips": ["0.0.0.0/0"]
        },
        {
          "direction": "in",
          "protocol": "tcp",
          "port": "443",
          "source_ips": ["0.0.0.0/0"]
        }
      ]
    }
  }
}

Deployment

Unlike managed platforms, Hetzner VMs require deployment configuration. WebKit generates:

  • Ansible playbooks for initial setup
  • GitHub Actions workflows for deployment
  • Docker configuration for containerised apps

Ansible provisioning

WebKit generates Ansible playbooks to configure your VM:

  • Install Docker and required packages
  • Configure firewall rules
  • Set up SSL certificates (Let's Encrypt)
  • Deploy your application

Run provisioning:

bash
webkit infra apply  # Creates VM
# Ansible runs automatically via GitHub Actions

Manual deployment

For manual deployments, SSH into your VM:

bash
ssh root@your-vm-ip
cd /opt/app
docker compose pull
docker compose up -d

Example: Self-hosted application

A Go API deployed on Hetzner with attached storage:

json
{
  "project": {
    "name": "my-api",
    "title": "My API",
    "repo": "github.com/myorg/my-api"
  },
  "apps": [
    {
      "name": "api",
      "type": "golang",
      "path": "./apps/api",
      "build": {
        "dockerfile": true,
        "port": 8080
      },
      "infrastructure": {
        "provider": "hetzner",
        "type": "vm",
        "config": {
          "size": "cx22",
          "location": "nbg1",
          "image": "ubuntu-22.04"
        }
      },
      "domains": {
        "primary": "api.example.com"
      }
    }
  ],
  "resources": [
    {
      "name": "uploads",
      "type": "volume",
      "provider": "hetzner",
      "config": {
        "size": 50,
        "location": "nbg1",
        "mount_point": "/data/uploads"
      }
    }
  ]
}

Comparison with DigitalOcean

FeatureHetznerDigitalOcean
Managed appsNoYes (App Platform)
VM pricingLowerHigher
Managed DBNoYes
European locationsExcellentGood
US locations2Many
ARM serversYesNo
Setup complexityHigherLower

Choose Hetzner when:

  • Cost is a priority
  • You need ARM servers
  • You're comfortable with VM management
  • Your users are primarily in Europe

Choose DigitalOcean when:

  • You want managed services
  • Simplicity is important
  • You need managed databases
  • Your users are globally distributed

Further reading

Released under the MIT Licence.