OpenMCF logoOpenMCF

Loading...

Hetzner Cloud Load Balancer

Deploys a Hetzner Cloud load balancer with configurable services (HTTP, HTTPS, TCP listeners), backend targets (servers, label selectors, external IPs), health checks, TLS termination, and optional private network attachment. This is the most feature-rich component in the Hetzner Cloud catalog — it bundles four provider resources into a single manifest that defines how traffic reaches your servers.

What Gets Created

  • Load Balancer — an hcloud_load_balancer resource provisioning a load balancer with the specified type, location, algorithm, labels, and delete protection.
  • Load Balancer Service (one per entry in services) — an hcloud_load_balancer_service resource configuring a listener with protocol, ports, HTTP settings (sticky sessions, TLS certificates, HTTP-to-HTTPS redirect), and health check.
  • Load Balancer Target (one per entry across serverTargets, labelSelectorTargets, and ipTargets) — an hcloud_load_balancer_target resource adding a backend. Server targets reference a Hetzner Cloud server by ID, label selector targets dynamically match servers by labels, and IP targets route to external addresses.
  • Load Balancer Network (created only when network is set) — an hcloud_load_balancer_network resource attaching the load balancer to a private network with an optional fixed IP and public interface control.

Prerequisites

  • Hetzner Cloud API token configured via environment variable (HCLOUD_TOKEN) or OpenMCF provider config
  • At least one backend — server targets require pre-existing servers (or HetznerCloudServer resources), label selector targets require servers with matching labels, IP targets require reachable external IPs
  • A private network if using the network attachment — either pre-existing or a HetznerCloudNetwork resource with a subnet in the same network zone as the load balancer's location
  • TLS certificates if configuring HTTPS services — either pre-existing certificate IDs or HetznerCloudCertificate resources referenced via valueFrom

Quick Start

Create a file load-balancer.yaml:

apiVersion: hetzner-cloud.openmcf.org/v1
kind: HetznerCloudLoadBalancer
metadata:
  name: my-lb
  labels:
    openmcf.org/provisioner: pulumi
    pulumi.openmcf.org/organization: my-org
    pulumi.openmcf.org/project: my-project
    pulumi.openmcf.org/stack.name: dev.HetznerCloudLoadBalancer.my-lb
spec:
  loadBalancerType: lb11
  location: fsn1
  services:
    - protocol: http
  serverTargets:
    - serverId:
        value: "12345"

Deploy:

openmcf apply -f load-balancer.yaml

This provisions an lb11 load balancer in Falkenstein with a single HTTP listener on port 80 forwarding to one server target.

Configuration Reference

Required Fields

FieldTypeDescriptionValidation
loadBalancerTypestringLoad balancer size. Available types: lb11 (25 targets, 10k conn/s), lb21 (75 targets, 20k conn/s), lb31 (150 targets, 40k conn/s). Can be changed after creation (in-place resize).min_len: 1
locationstringHetzner Cloud location for the load balancer. Known locations: fsn1, nbg1, hel1, ash, hil, sin. Changing this forces replacement.min_len: 1
servicesService[]Listeners that the load balancer exposes. Each service binds to a listen port and forwards traffic to targets.min_items: 1
services[].protocolenumListener protocol: http, https, or tcp. Changing forces service replacement.required, defined_only

Optional Fields

FieldTypeDefaultDescription
algorithmenumround_robinTraffic distribution algorithm. Values: round_robin, least_connections.
deleteProtectionboolfalsePrevent accidental deletion via the Hetzner Cloud API.
services[].listenPortint80 (http), 443 (https)Port the load balancer listens on. Must be unique across services. Required for tcp. Changing forces replacement.
services[].destinationPortintsame as listenPortPort on target servers that receives forwarded traffic. Required for tcp.
services[].proxyprotocolboolfalseEnable PROXY protocol v1 when forwarding to targets. Target must support PROXY protocol.
services[].httpobjectunsetHTTP-level configuration. Only applicable for http and https protocols.
services[].http.stickySessionsboolfalseEnable cookie-based session affinity.
services[].http.cookieNamestringHCLBSTICKYSticky session cookie name. Only used when stickySessions is true.
services[].http.cookieLifetimeint300Sticky session cookie lifetime in seconds. Only used when stickySessions is true.
services[].http.certificateIdsStringValueOrRef[]emptyTLS certificates for HTTPS termination. Can reference HetznerCloudCertificate resources via valueFrom. Only used when protocol is https.
services[].http.redirectHttpboolfalseRedirect HTTP traffic on port 80 to HTTPS. Only valid for https services on port 443.
services[].healthCheckobjectprovider defaultCustom health check. When omitted, the provider creates a default matching the service protocol and destination port.
services[].healthCheck.protocolenummatches serviceHealth check protocol: http, https, or tcp. HTTPS services default to http health checks.
services[].healthCheck.portintmatches destinationPortPort to health-check on the target.
services[].healthCheck.intervalint15Seconds between health checks.
services[].healthCheck.timeoutint10Seconds to wait for a response. Must be less than interval.
services[].healthCheck.retriesint3Consecutive failures before marking target unhealthy.
services[].healthCheck.httpobjectunsetHTTP-specific health check settings. Only used when health check protocol is http or https.
services[].healthCheck.http.domainstringtarget IPHTTP Host header for the health check request.
services[].healthCheck.http.pathstring/URL path for the health check request.
services[].healthCheck.http.responsestringemptyExpected response body substring.
services[].healthCheck.http.tlsboolfalseVerify target TLS certificate during health check. Only meaningful for https protocol.
services[].healthCheck.http.statusCodesstring[]["2??", "3??"]Expected HTTP status codes. Uses wildcard notation: 2?? matches any 2xx status.
serverTargetsServerTarget[]emptyStatic server backends.
serverTargets[].serverIdStringValueOrRef—Server to add as a target. Can reference HetznerCloudServer resources via valueFrom. Required within each entry. Changing forces replacement.
serverTargets[].usePrivateIpboolfalseRoute traffic over private network instead of public IP. Requires network attachment.
labelSelectorTargetsLabelSelectorTarget[]emptyDynamic server backends selected by labels.
labelSelectorTargets[].selectorstring—Hetzner Cloud label selector expression (e.g., env=production,role=web). Required within each entry. Changing forces replacement.
labelSelectorTargets[].usePrivateIpboolfalseRoute traffic over private network. Requires network attachment.
ipTargetsIpTarget[]emptyExternal IP backends for targets outside Hetzner Cloud.
ipTargets[].ipstring—IP address of the external backend. Required within each entry. Changing forces replacement.
networkobjectunsetPrivate network attachment. At most one network per load balancer.
network.networkIdStringValueOrRef—Network to attach to. Can reference HetznerCloudNetwork resources via valueFrom. Required when network is set. Changing forces replacement.
network.ipstringauto-assignedFixed private IP within the network's subnet range.
network.enablePublicInterfacebooltrueEnable the load balancer's public interface. When false, the LB is only reachable via its private IP.

Examples

Minimal HTTP Load Balancer

An lb11 load balancer with an HTTP listener on port 80 forwarding to a single server target.

apiVersion: hetzner-cloud.openmcf.org/v1
kind: HetznerCloudLoadBalancer
metadata:
  name: web-lb
  labels:
    openmcf.org/provisioner: pulumi
    pulumi.openmcf.org/organization: my-org
    pulumi.openmcf.org/project: my-project
    pulumi.openmcf.org/stack.name: dev.HetznerCloudLoadBalancer.web-lb
spec:
  loadBalancerType: lb11
  location: fsn1
  services:
    - protocol: http
  serverTargets:
    - serverId:
        value: "12345"

HTTPS with TLS Termination and Health Check

An HTTPS load balancer using a certificate from a HetznerCloudCertificate resource. HTTP traffic is redirected to HTTPS. A custom health check verifies the backend on /health.

apiVersion: hetzner-cloud.openmcf.org/v1
kind: HetznerCloudLoadBalancer
metadata:
  name: web-https-lb
  org: acme-corp
  env: staging
  labels:
    openmcf.org/provisioner: pulumi
    pulumi.openmcf.org/organization: acme-corp
    pulumi.openmcf.org/project: web-platform
    pulumi.openmcf.org/stack.name: staging.HetznerCloudLoadBalancer.web-https-lb
spec:
  loadBalancerType: lb11
  location: fsn1
  services:
    - protocol: https
      destinationPort: 8080
      http:
        certificateIds:
          - valueFrom:
              kind: HetznerCloudCertificate
              name: web-cert
              fieldPath: status.outputs.certificate_id
        redirectHttp: true
      healthCheck:
        protocol: http
        port: 8080
        interval: 10
        timeout: 5
        retries: 3
        http:
          path: /health
  serverTargets:
    - serverId:
        valueFrom:
          kind: HetznerCloudServer
          name: web-01
          fieldPath: status.outputs.server_id
    - serverId:
        valueFrom:
          kind: HetznerCloudServer
          name: web-02
          fieldPath: status.outputs.server_id

Private Network Load Balancer with Label Selector Targets

A load balancer on a private network using label selectors to dynamically discover backend servers. All traffic flows over the private network.

apiVersion: hetzner-cloud.openmcf.org/v1
kind: HetznerCloudLoadBalancer
metadata:
  name: internal-lb
  org: acme-corp
  env: production
  labels:
    openmcf.org/provisioner: pulumi
    pulumi.openmcf.org/organization: acme-corp
    pulumi.openmcf.org/project: infrastructure
    pulumi.openmcf.org/stack.name: production.HetznerCloudLoadBalancer.internal-lb
spec:
  loadBalancerType: lb21
  location: fsn1
  algorithm: least_connections
  services:
    - protocol: http
      destinationPort: 8080
      healthCheck:
        protocol: http
        port: 8080
        http:
          path: /ready
  labelSelectorTargets:
    - selector: "env=production,role=web"
      usePrivateIp: true
  network:
    networkId:
      valueFrom:
        kind: HetznerCloudNetwork
        name: main-vpc
        fieldPath: status.outputs.network_id
    ip: "10.0.1.100"
    enablePublicInterface: true

Full-Featured Production Load Balancer

A production load balancer with HTTPS, sticky sessions, multiple target types, private networking, custom health checks, and delete protection.

apiVersion: hetzner-cloud.openmcf.org/v1
kind: HetznerCloudLoadBalancer
metadata:
  name: prod-lb
  org: acme-corp
  env: production
  labels:
    openmcf.org/provisioner: pulumi
    pulumi.openmcf.org/organization: acme-corp
    pulumi.openmcf.org/project: infrastructure
    pulumi.openmcf.org/stack.name: production.HetznerCloudLoadBalancer.prod-lb
spec:
  loadBalancerType: lb31
  location: fsn1
  algorithm: least_connections
  deleteProtection: true
  services:
    - protocol: https
      destinationPort: 8080
      http:
        certificateIds:
          - valueFrom:
              kind: HetznerCloudCertificate
              name: prod-cert
              fieldPath: status.outputs.certificate_id
        redirectHttp: true
        stickySessions: true
        cookieName: PRODSESSION
        cookieLifetime: 1800
      healthCheck:
        protocol: http
        port: 8080
        interval: 10
        timeout: 5
        retries: 3
        http:
          path: /health
          statusCodes:
            - "200"
    - protocol: tcp
      listenPort: 6379
      destinationPort: 6379
      healthCheck:
        protocol: tcp
        port: 6379
        interval: 10
        timeout: 5
        retries: 2
  serverTargets:
    - serverId:
        valueFrom:
          kind: HetznerCloudServer
          name: web-01
          fieldPath: status.outputs.server_id
      usePrivateIp: true
    - serverId:
        valueFrom:
          kind: HetznerCloudServer
          name: web-02
          fieldPath: status.outputs.server_id
      usePrivateIp: true
  labelSelectorTargets:
    - selector: "env=production,role=web"
      usePrivateIp: true
  ipTargets:
    - ip: "203.0.113.50"
  network:
    networkId:
      valueFrom:
        kind: HetznerCloudNetwork
        name: main-vpc
        fieldPath: status.outputs.network_id
    ip: "10.0.1.200"
    enablePublicInterface: true

Stack Outputs

OutputTypeDescription
load_balancer_idstringHetzner Cloud numeric ID of the created load balancer. Can be referenced by other components via StringValueOrRef.
ipv4_addressstringThe public IPv4 address assigned to the load balancer. Empty if the public interface is disabled via network.enablePublicInterface = false.
ipv6_addressstringThe public IPv6 address assigned to the load balancer. Empty if the public interface is disabled.

Related Components

  • HetznerCloudServer — Servers added as load balancer backends, referenced via serverTargets[].serverId
  • HetznerCloudNetwork — Private network for internal traffic routing, referenced via network.networkId
  • HetznerCloudCertificate — TLS certificates for HTTPS termination, referenced via services[].http.certificateIds
  • HetznerCloudFirewall — Network security rules applied to backend servers
  • HetznerCloudSshKey — SSH keys for accessing backend servers

Next article

Hetzner Cloud Network

Hetzner Cloud Network Creates a private network in Hetzner Cloud with subnets and optional static routes. The network provides isolated IPv4 connectivity between cloud resources using RFC 1918 addresses. Subnets are declared inline and can span multiple network zones for cross-region private connectivity. At least one subnet is required because servers and load balancers attach to subnets, not directly to the network. What Gets Created Network — an hcloudnetwork resource with a top-level CIDR...
Read next article
Presets
3 ready-to-deploy configurationsView presets →