chaudrondocs

Providers

Hetzner Cloud

Servers, SSH keys, firewalls, IPs, volumes, networks, load balancers and snapshots.

On this page
scheme
(use-modules (chaudron) (chaudron hetzner))

Setup

Create a token in the Hetzner Console: open the project, then Security, API tokens, with Read & Write permissions. chaudron reads it from HCLOUD_TOKEN, or from with-hetzner:

scheme
(with-hetzner token
  (with-stage "prod" ...))

See Credentials for the other ways to give it.

A complete example

deploy.scm
(with-stage "prod"
  (define key
    (hetzner-ssh-key "me" #:public-key-file "~/.ssh/id_ed25519.pub"))

  (define web
    (hetzner-firewall "web"
                      #:rules (list (allow-in 'tcp 22)
                                    (allow-in 'tcp 443)
                                    (allow-in 'tcp "8000-8100"
                                              #:from '("10.0.0.0/8"))
                                    (allow-in 'icmp))))

  (define ip   (hetzner-primary-ip "forge" #:location "fsn1"))
  (define data (hetzner-volume "data" #:size 20 #:location "fsn1"))
  (define lan  (hetzner-network "lan" #:ip-range "10.0.0.0/16"))

  (define forge
    (hetzner-server "forge"
                    #:type "cx23"
                    #:location "fsn1"
                    #:ssh-keys (list key)
                    #:firewalls (list web)
                    #:ipv4 ip              ;keeps its address when replaced
                    #:volumes (list data)  ;mounted under /mnt
                    #:networks (list lan)
                    #:backups? #t
                    #:protected? #t))

  (hetzner-load-balancer "front"
                         #:location "fsn1"
                         #:services (list (forward 'http 80 #:to 8080))
                         #:targets (list forge)
                         #:network lan))

What every resource shares

  • Names. At Hetzner, a resource is named after its resource name and its stage, forge-prod for forge in "prod", so that stages can share a project. #:name sets another name.
  • Labels. #:labels, an association list of strings, sets your own labels, such as '(("role" . "web")). chaudron adds chaudron/stage to every resource.
  • Protection. #:protected? #t makes Hetzner refuse to delete the resource, and to rebuild a server, including through chaudron: turn it off before deleting it.

hetzner-server

A server.

ArgumentDefault
#:typerequiredthe server type, such as "cx23"
#:locationrequiredsuch as "fsn1", "nbg1" or "hel1"
#:image"debian-12"an image name, or a snapshot
#:ssh-keys'()SSH keys for root
#:firewalls'()firewalls
#:volumes'()volumes, mounted under /mnt
#:networks'()private networks
#:ipv4, #:ipv6new addressesprimary IPs
#:user-datanonea cloud-init configuration
#:backups?#fdaily backups by Hetzner
#:labels, #:protected?, #:namesee above

Outputs: id, ipv4, ipv6, private-ipv4.

Changing the location or the image replaces the server, losing the data on its disk, but not its volumes, and not its address if it has a primary IP. Everything else changes in place:

  • changing the type or the primary IPs powers the server off for a moment; its disk is not grown, so that it can be downgraded again;
  • #:ssh-keys and #:user-data are only used when the server is created;
  • #:user-data is stored in the state: no secrets in it.

hetzner-ssh-key

An SSH key, to give to servers.

ArgumentDefault
#:public-keythe key itself, as a string
#:public-key-fileor a file to read it from, such as "~/.ssh/id_ed25519.pub"
#:labels, #:namesee above

Outputs: id, fingerprint. Changing the key replaces it.

Hetzner accepts each key only once per project: two stages declaring the same key in one project fail with SSH key not unique. Keep the key in a stage of its own, as in Staging and production.

hetzner-firewall

A firewall, filtering the traffic coming to the servers it is given to. Outgoing traffic is always allowed.

ArgumentDefault
#:rules'()rules made with allow-in
#:labels, #:namesee above

Output: id. It changes in place.

(allow-in protocol [port] #:from networks) allows incoming protocol traffic, 'tcp, 'udp or 'icmp, to port, a number or a range such as "8000-8100", from networks, by default every address.

The rules are not checked for drift: a rule added by hand in the console stays until the rules change in the program.

hetzner-primary-ip

A public address that outlives servers: give it to a server with #:ipv4 or #:ipv6, and the server can be replaced without changing address.

ArgumentDefault
#:locationrequiredthe location of the servers it will go to
#:type'ipv4or 'ipv6
#:labels, #:protected?, #:namesee above

Outputs: id, ip. Changing its type or location replaces it.

hetzner-volume

Block storage, mounted under /mnt on the server it is given to.

ArgumentDefault
#:sizerequiredin gigabytes; it can only grow
#:locationrequired
#:format"ext4"the file system
#:labels, #:protected?, #:namesee above

Outputs: id, linux-device. Changing its location or format replaces it.

hetzner-network

A private network between servers and load balancers.

ArgumentDefault
#:ip-range"10.0.0.0/16"it can only grow
#:subnetsthe whole rangea list of ranges
#:zone"eu-central"the network zone
#:labels, #:protected?, #:namesee above

Output: id. Changing its zone replaces it. A server's address on its first network is its private-ipv4 output.

hetzner-load-balancer

A load balancer, sending traffic to servers.

ArgumentDefault
#:locationrequired
#:type"lb11"
#:algorithm'round-robinor 'least-connections
#:services'()services made with forward
#:targets'()servers
#:networknonea network, to reach the targets privately
#:labels, #:protected?, #:namesee above

Outputs: id, ipv4, ipv6. Changing its location or network replaces it.

(forward protocol port #:to target-port) forwards 'tcp or 'http traffic from port on the load balancer to target-port on the targets, by default the same port.

hetzner-snapshot

An image of a server's disk, taken once, when it is created. It can be the #:image of other servers.

ArgumentDefault
#:serverrequired
#:descriptionthe resource name
#:labels, #:protected?see above

Output: id. Changing its server replaces it. For a consistent copy, power the server off first.