Hetzner Compose

Hetzner Cloud platform with Terraform (VM provisioning) and Docker Compose (services). Provisions a cloud server in Falkenstein with Traefik reverse proxy, an application stack, and INWX DNS records.

Architecture Overview

Layer

Tool

Purpose

Provider

Hetzner Cloud (Falkenstein DC)

Resource

Terraform

CX31 cloud server with Ubuntu 24.04

DNS

Terraform

INWX zone and A records

Namespace

Compose

Services group (Traefik + app + database)

Deployment

Production instance


Configuration

apiVersion: strata.huybrechts.xyz/v1
kind: configuration
meta:
  name: hetzner_config
  annotations:
    description: Hetzner Cloud platform — Terraform + Docker Compose with INWX DNS
  labels:
    version: "1.0.0"
  tags: [hetzner, inwx, configuration]
spec:
  layering:
    - name: environment
      description: "Deployment environment (dev, staging, prd)"
      required: true

  deployment:
    additional_properties: false
    properties:
      environment:
        pattern: "^(dev|staging|prd)$"
        required: true
        description: "Target environment"

  zones:
    - name: eu_central
      description: "Central Europe (Falkenstein, Nuremberg)"
      regions:
        - fsn1
        - nbg1
    - name: eu_west
      description: "Western Europe (Helsinki, Ashburn)"
      regions:
        - hel1

  remotes:
    - name: hetzner_platform
      type: gitops
      repository: git@github.com:your-org/hetzner-platform.git
      reference: main
      source_path: .
      deploy_path: .

  integrations:
    - name: git
      type: git
      capabilities: [repository]
      required: true
      validation:
        command: git --version
        min_version: "2.30.0"
      authentication:
        method: cli

    - name: terraform
      type: terraform
      capabilities: [infrastructure]
      required: true
      validation:
        command: terraform --version
        min_version: "1.6.0"
      authentication:
        method: cli

    - name: docker
      type: docker
      capabilities: [container]
      required: true
      validation:
        command: docker --version
        min_version: "24.0.0"
      authentication:
        method: cli

Workspace

apiVersion: strata.huybrechts.xyz/v1
kind: workspace
meta:
  name: hetzner_platform
  annotations:
    description: Hetzner Cloud workspace — Terraform provisions VMs, Compose deploys services
  labels:
    version: "1.0.0"
  tags: [hetzner, workspace]
spec:
  providers:
    - name: hetzner_fsn1
      file: "@hetzner_platform/stack/hetzner-provider-fsn1.yaml"

  provisioners:
    - name: terraform
      provisioner: terraform
      source:
        repository: hetzner_platform
        source_path: terraform

    - name: compose
      provisioner: compose
      source:
        repository: hetzner_platform
        source_path: services

  topology:
    - name: app_servers
      provider: hetzner_fsn1
      provisioner: terraform
      type: docker_host
      components:
        - resource: vm_app
      namespaces:
        - namespace: services

  resources:
    - name: vm_app
      file: "@hetzner_platform/stack/hetzner-res-app.yaml"
      description: Application server

  namespaces:
    - name: services
      file: "@hetzner_platform/stack/hetzner-ns-services.yaml"

Provider

apiVersion: strata.huybrechts.xyz/v1
kind: provider
meta:
  name: hetzner_fsn1
  annotations:
    description: Hetzner Cloud — Falkenstein datacenter
  labels:
    version: "1.0.0"
  tags: [hetzner, provider, falkenstein]
spec:
  properties:
    type: hetzner
    region: fsn1

Resource

Application Server

apiVersion: strata.huybrechts.xyz/v1
kind: resource
meta:
  name: hetzner_vm_app
  annotations:
    description: Hetzner Cloud server for application workloads
  labels:
    version: "1.0.0"
  tags: [hetzner, resource, server]
spec:
  properties:
    provider_type: hetzner
    resource_type: cloud_server
    category: compute
    subcategory: virtual_machine
  configuration:
    server_type: cx31
    image: ubuntu-24.04
    location: fsn1
    ssh_keys: [deploy-key]
    backups: true

DNS

INWX DNS zone with records pointing to the server’s public IP.

apiVersion: strata.huybrechts.xyz/v1
kind: dns
meta:
  name: hetzner_dns_inwx
  annotations:
    description: INWX DNS records for Hetzner platform services
  labels:
    version: "1.0.0"
  tags: [hetzner, inwx, dns]
spec:
  provider: inwx
  references:
    variables:
      - SERVER_IP
  zones:
    - name: example.com
      ttl: 3600
      records:
        - name: "@"
          type: A
          var: SERVER_IP
        - name: "www"
          type: CNAME
          value: "example.com."
        - name: "api"
          type: A
          var: SERVER_IP
        - name: "traefik"
          type: A
          var: SERVER_IP

Namespace

apiVersion: strata.huybrechts.xyz/v1
kind: namespace
meta:
  name: hetzner_ns_services
  annotations:
    description: Application services namespace
  labels:
    version: "1.0.0"
  tags: [hetzner, namespace, services]
spec:
  modules:
    - name: traefik
      file: "@hetzner_platform/stack/hetzner-mod-traefik.yaml"
    - name: app
      file: "@hetzner_platform/stack/hetzner-mod-app.yaml"

Modules

Traefik Reverse Proxy

apiVersion: strata.huybrechts.xyz/v1
kind: module
meta:
  name: hetzner_mod_traefik
  annotations:
    description: Traefik reverse proxy with Let's Encrypt TLS
  labels:
    version: "1.0.0"
  tags: [hetzner, module, traefik]
spec:
  type: compose
  source:
    repository: hetzner_platform
    source_path: services/traefik
  services:
    - name: traefik
      image: traefik:v3.1
      restart: unless-stopped
      ports:
        - "80:80"
        - "443:443"
        - "8080:8080"

Application Stack

apiVersion: strata.huybrechts.xyz/v1
kind: module
meta:
  name: hetzner_mod_app
  annotations:
    description: Application API and database services
  labels:
    version: "1.0.0"
  tags: [hetzner, module, app, compose]
spec:
  type: compose
  source:
    repository: hetzner_platform
    source_path: services/app
  references:
    variables:
      - DATABASE_URL
      - APP_PORT
    secrets:
      - DB_PASSWORD
  services:
    - name: app
      image: "your-org/app:latest"
      restart: unless-stopped
      ports:
        - "8080:8080"
    - name: postgres
      image: postgres:16-alpine
      restart: unless-stopped
      ports:
        - "5432:5432"

Environment

apiVersion: strata.huybrechts.xyz/v1
kind: environment
meta:
  name: hetzner_env_prd
  annotations:
    description: Production environment for Hetzner Cloud platform
  labels:
    version: "1.0.0"
  tags: [hetzner, production, environment]
spec:
  variables:
    - key: WORKSPACE
      store: constant
      value: hetzner_platform
    - key: ENVIRONMENT
      store: constant
      value: prd
    - key: HCLOUD_LOCATION
      store: constant
      value: fsn1
    - key: DOMAIN
      store: constant
      value: example.com

  secrets:
    - key: HCLOUD_TOKEN
      store: environment
      value: HCLOUD_TOKEN
    - key: INWX_USERNAME
      store: environment
      value: INWX_USERNAME
    - key: INWX_PASSWORD
      store: environment
      value: INWX_PASSWORD
    - key: SSH_PRIVATE_KEY
      store: environment
      value: SSH_PRIVATE_KEY

Deployment

apiVersion: strata.huybrechts.xyz/v1
kind: deployment
meta:
  name: hetzner_deploy_prd
  annotations:
    description: Production deployment for Hetzner Cloud platform
  labels:
    version: "1.0.0"
  tags: [hetzner, production, deployment]
spec:
  layers:
    environment: prd

  properties:
    environment: prd

  workspace:
    name: hetzner_platform
    description: Hetzner Cloud Platform
    file: "@hetzner_platform/stack/hetzner-ws-platform.yaml"

  environments:
    - "@hetzner_platform/environments/hetzner-env-prd.yaml"

  stages:
    - name: infrastructure
      provisioner: terraform
      scope: all
      on_failure: stop

    - name: services
      provisioner: compose
      scope: all
      depends_on: [infrastructure]
      on_failure: stop