Skip to content

How to migrate from Hetzner Cloud to Quake AI with OpenTofu

Migration · Updated Jun 2026

Coming from another cloud?

▸Hetzner·Server, Images

Imageshigh

  • Includes system images (OS), user images (snapshots/backups).
  • API /v1/images; create via server action create_image (type=snapshot/backup).
  • Billed per GB/month; backups cost 20% of server price.
  • No direct image upload; custom via ISO attach or rebuild.
Hetzner docs ↗

How to migrate from Hetzner Cloud to Quake AI with OpenTofu

Hetzner Cloud and Quake AI attract similar audiences: cost-conscious engineers who self-manage infrastructure. If you already use Terraform or OpenTofu with the Hetzner Cloud provider, migrating to Quake AI is a provider swap with resource remapping.

Conceptual mapping#

Both platforms offer similar primitives, but the APIs and resource names differ:

ConceptHetzner Cloud (hcloud)Quake AI (OpenStack)
Providerhetznercloud/hcloudterraform-provider-openstack/openstack
Serverhcloud_serveropenstack_compute_instance_v2
Server typecx22, cpx31, etc.s1a.small, s1a.medium, m2a.large, etc.
SSH keyhcloud_ssh_keyopenstack_compute_keypair_v2
Floating IPhcloud_floating_ipopenstack_networking_floatingip_v2
Firewallhcloud_firewallopenstack_networking_secgroup_v2 + rules
Volumehcloud_volumeopenstack_blockstorage_volume_v3
Networkhcloud_network + hcloud_network_subnetopenstack_networking_network_v2 + openstack_networking_subnet_v2
Load balancerhcloud_load_balancerSelf-managed reverse proxy or API gateway instance with a floating IP
Placement grouphcloud_placement_groupopenstack_compute_servergroup_v2
ImageHetzner base imagesQuake AI images (Ubuntu, Debian, etc.)

Resource translation examples#

Server#

Hetzner:

HCL
resource "hcloud_server" "web" {
  name        = "web-1"
  server_type = "cx22"
  image       = "ubuntu-24.04"
  location    = "fsn1"

  ssh_keys = [hcloud_ssh_key.main.id]
}

Quake AI (private network, router, floating IP, and volume-backed boot; same topology as the Simple VM template):

HCL
data "openstack_images_image_v2" "ubuntu" {
  name        = "Ubuntu-24.04"
  most_recent = true
}

data "openstack_networking_network_v2" "external" {
  name = "PublicStatic"
}

resource "openstack_networking_network_v2" "private" {
  name = "web-net"
}

resource "openstack_networking_subnet_v2" "private" {
  network_id = openstack_networking_network_v2.private.id
  cidr       = "192.168.10.0/24"
  ip_version = 4
}

resource "openstack_networking_router_v2" "router" {
  name                = "web-router"
  external_network_id = data.openstack_networking_network_v2.external.id
}

resource "openstack_networking_router_interface_v2" "private" {
  router_id = openstack_networking_router_v2.router.id
  subnet_id = openstack_networking_subnet_v2.private.id
}

resource "openstack_networking_port_v2" "web" {
  network_id = openstack_networking_network_v2.private.id

  fixed_ip {
    subnet_id = openstack_networking_subnet_v2.private.id
  }

  depends_on = [openstack_networking_router_interface_v2.private]
}

resource "openstack_compute_instance_v2" "web" {
  name        = "web-1"
  flavor_name = "s1a.small"
  key_pair    = openstack_compute_keypair_v2.main.name

  block_device {
    uuid                  = data.openstack_images_image_v2.ubuntu.id
    source_type           = "image"
    destination_type      = "volume"
    volume_size           = 20
    boot_index            = 0
    delete_on_termination = true
  }

  network {
    port = openstack_networking_port_v2.web.id
  }
}

resource "openstack_networking_floatingip_v2" "web" {
  pool = data.openstack_networking_network_v2.external.name
}

resource "openstack_networking_floatingip_associate_v2" "web" {
  floating_ip = openstack_networking_floatingip_v2.web.address
  port_id     = openstack_networking_port_v2.web.id
}

Firewall to security group#

Hetzner:

HCL
resource "hcloud_firewall" "web" {
  name = "web-firewall"

  rule {
    direction = "in"
    protocol  = "tcp"
    port      = "80"
    source_ips = ["0.0.0.0/0"]
  }

  rule {
    direction = "in"
    protocol  = "tcp"
    port      = "443"
    source_ips = ["0.0.0.0/0"]
  }
}

Quake AI:

HCL
resource "openstack_networking_secgroup_v2" "web" {
  name = "web-secgroup"
}

resource "openstack_networking_secgroup_rule_v2" "http" {
  security_group_id = openstack_networking_secgroup_v2.web.id
  direction         = "ingress"
  ethertype         = "IPv4"
  protocol          = "tcp"
  port_range_min    = 80
  port_range_max    = 80
  remote_ip_prefix  = "0.0.0.0/0"
}

resource "openstack_networking_secgroup_rule_v2" "https" {
  security_group_id = openstack_networking_secgroup_v2.web.id
  direction         = "ingress"
  ethertype         = "IPv4"
  protocol          = "tcp"
  port_range_min    = 443
  port_range_max    = 443
  remote_ip_prefix  = "0.0.0.0/0"
}

Volume#

Hetzner:

HCL
resource "hcloud_volume" "data" {
  name     = "data-vol"
  size     = 50
  location = "fsn1"
  format   = "ext4"
}

Quake AI:

HCL
resource "openstack_blockstorage_volume_v3" "data" {
  name = "data-vol"
  size = 50
}

Volume attachment and formatting happen through openstack_compute_volume_attach_v2 and cloud-init, respectively.

Migration workflow#

  1. Export your Hetzner state. Run tofu show to document current resources.
  2. Map server types to Quake AI flavors. Compare vCPU/RAM specs between Hetzner server types and Quake AI flavors in the dashboard.
  3. Rewrite the provider block. Replace hcloud with openstack and configure environment variable authentication.
  4. Translate resources. Use the mapping table above. Start with a single server and security group.
  5. Set up data migration. For volumes, use rsync or scp to copy data between instances. For S3-compatible storage, use rclone.
  6. Test with tofu plan. Validate the configuration before applying.
  7. Apply and verify. Deploy on Quake AI and confirm services are reachable.

For an existing hcloud_load_balancer, deploy the Edge Reverse Proxy template and translate its services and targets into proxy routes that use backend private addresses. Use the API Gateway template when the workload needs API-specific routing and policy controls.

Key differences from Hetzner#

  • Authentication. Hetzner uses a single API token. Quake AI uses OpenStack Keystone with username, password, project, and domain, set via environment variables.
  • Networking model. Hetzner auto-assigns a public IPv4. Quake AI uses floating IPs that you explicitly associate with instances.
  • Firewall vs security group. Hetzner firewalls are standalone resources applied to servers. Quake AI security groups are attached to ports/instances with individual rules as separate resources.
  • Object storage. Hetzner does not offer S3-compatible storage. Quake AI does; see the S3 Storage with ACLs template.
  • Pricing model. Both offer fixed monthly pricing. Compare per-resource costs in the Quake AI dashboard.

See also#

Usage Guidelines

The sample code, software libraries, command line tools, proofs of concept, templates, and other related technology on this page (including any of the foregoing that is provided by Quake AI personnel) is provided to you as Quake AI Content under the Quake AI Customer Agreement, or the relevant written agreement between you and Quake AI (whichever applies). Do not use this Quake AI Content in your production accounts, or on production or other critical data. You are responsible for testing, securing, and optimizing the Quake AI Content (such as sample code) as appropriate for production grade use based on your specific quality control practices and standards. Deploying Quake AI Content may incur Quake AI charges for creating or using Quake AI chargeable resources, such as running Compute instances or storing data in Object Storage. Your use is also subject to the Acceptable Use Policy.

Comparisons to third-party providers in this material reflect publicly documented behavior as of the validation date below. Pricing, quotas, service limits, and feature availability change frequently on every cloud. Verify provider-specific claims against the provider's own current documentation before relying on them for a procurement, architecture, or migration decision.

For the full policy, see Usage Guidelines.

Last validated: 22.06.2026

Was this page helpful?