> ## Documentation Index
> Fetch the complete documentation index at: https://docs.siderolabs.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Hetzner

> Creating a cluster via the CLI (hcloud) on Hetzner.

export const release_v1_7 = 'v1.7.6';

export const VersionWarningBanner = () => {
  const latestVersion = "v1.13";
  const [latestUrl, setLatestUrl] = useState(null);
  const [currentVersion, setCurrentVersion] = useState(null);
  const [isBeta, setIsBeta] = useState(false);
  const parseVersion = v => v.replace("v", "").split(".").map(Number);
  const isGreaterVersion = (a, b) => {
    const [aMajor, aMinor] = parseVersion(a);
    const [bMajor, bMinor] = parseVersion(b);
    if (aMajor > bMajor) return true;
    if (aMajor === bMajor && aMinor > bMinor) return true;
    return false;
  };
  useEffect(() => {
    if (typeof window === "undefined") return;
    const {pathname, hash, search} = window.location;
    const match = pathname.match(/\/talos\/(v\d+\.\d+)\//);
    if (!match) return;
    const detectedVersion = match[1];
    if (detectedVersion === latestVersion) return;
    setCurrentVersion(detectedVersion);
    if (isGreaterVersion(detectedVersion, latestVersion)) {
      setIsBeta(true);
    }
    const newPath = pathname.replace(`/talos/${detectedVersion}/`, `/talos/${latestVersion}/`);
    setLatestUrl(`${newPath}${search}${hash}`);
  }, []);
  if (!latestUrl || !currentVersion) return null;
  return <div className="not-prose sticky top-6 z-50 my-6">
      <div className="border border-yellow-500/30 bg-yellow-500/10 px-4 py-3 rounded-xl">
        <div className="text-sm">
          {isBeta ? <>
              ⚠️ You are viewing a <strong>beta version</strong> of Talos ({currentVersion}).
              This version may be unstable.
              <a href={latestUrl} className="ml-2 underline text-yellow-400 hover:text-yellow-300 font-medium">
                View latest stable version {latestVersion} →
              </a>
            </> : <>
              ⚠️ You are viewing an older version of Talos ({currentVersion}).
              <a href={latestUrl} className="ml-2 underline text-yellow-400 hover:text-yellow-300 font-medium">
                View the latest version {latestVersion} →
              </a>
            </>}
        </div>
      </div>
    </div>;
};

<VersionWarningBanner />

## Upload image

Hetzner Cloud does not support uploading custom images.
You can email their support to get a Talos ISO uploaded by following [issues:3599](https://github.com/siderolabs/talos/issues/3599#issuecomment-841172018) or you can prepare image snapshot by yourself.

There are two options to upload your own.

1. Run an instance in rescue mode and replace the system OS with the Talos image
2. Use [Hashicorp packer](https://www.packer.io/docs/builders/hetzner-cloud) to prepare an Image

### Rescue mode

Create a new Server in the Hetzner console.
Enable the Hetzner Rescue System for this server and reboot.
Upon a reboot, the server will boot a special minimal Linux distribution designed for repair and reinstall.
Once running, login to the server using `ssh` to prepare the system disk by doing the following:

<CodeBlock lang="sh">
  {`
    # Check that you in Rescue mode
    df

    ### Result is like:
    # udev                   987432         0    987432   0% /dev
    # 213.133.99.101:/nfs 308577696 247015616  45817536  85% /root/.oldroot/nfs
    # overlay                995672      8340    987332   1% /
    # tmpfs                  995672         0    995672   0% /dev/shm
    # tmpfs                  398272       572    397700   1% /run
    # tmpfs                    5120         0      5120   0% /run/lock
    # tmpfs                  199132         0    199132   0% /run/user/0

    # Download the Talos image
    cd /tmp
    wget -O /tmp/talos.raw.xz https://factory.talos.dev/image/376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba/${release_v1_7 }/hcloud-amd64.raw.xz
    # Replace system
    xz -d -c /tmp/talos.raw.xz | dd of=/dev/sda && sync
    # shutdown the instance
    shutdown -h now
    `}
</CodeBlock>

To make sure disk content is consistent, it is recommended to shut the server down before taking an image (snapshot).
Once shutdown, simply create an image (snapshot) from the console.
You can now use this snapshot to run Talos on the cloud.

### Packer

Install [packer](https://learn.hashicorp.com/tutorials/packer/get-started-install-cli) to the local machine.

Create a config file for packer to use:

<CodeBlock lang="hcl">
  {`
    # hcloud.pkr.hcl

    packer {
    required_plugins {
      hcloud = {
        source  = "github.com/hetznercloud/hcloud"
        version = "~> 1"
      }
    }
    }

    variable "talos_version" {
    type    = string
    default = "${release_v1_7 }"
    }

    variable "arch" {
    type    = string
    default = "amd64"
    }

    variable "server_type" {
    type    = string
    default = "cx11"
    }

    variable "server_location" {
    type    = string
    default = "hel1"
    }

    locals {
    image = "https://factory.talos.dev/image/376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba/\${var.talos_version}/hcloud-\${var.arch}.raw.xz"
    }

    source "hcloud" "talos" {
    rescue       = "linux64"
    image        = "debian-11"
    location     = "\${var.server_location}"
    server_type  = "\${var.server_type}"
    ssh_username = "root"

    snapshot_name   = "talos system disk - \${var.arch} - \${var.talos_version}"
    snapshot_labels = {
      type    = "infra",
      os      = "talos",
      version = "\${var.talos_version}",
      arch    = "\${var.arch}",
    }
    }

    build {
    sources = ["source.hcloud.talos"]

    provisioner "shell" {
      inline = [
        "apt-get install -y wget",
        "wget -O /tmp/talos.raw.xz \${local.image}",
        "xz -d -c /tmp/talos.raw.xz | dd of=/dev/sda && sync",
      ]
    }
    }
    `}
</CodeBlock>

Additionally you could create a file containing

```hcl theme={null}
arch            = "arm64"
server_type     = "cax11"
server_location = "fsn1"
```

and build the snapshot for arm64.

Create a new image by issuing the commands shown below.
Note that to create a new API token for your Project, switch into the Hetzner Cloud Console choose a Project, go to Access → Security, and create a new token.

```bash theme={null}
# First you need set API Token
export HCLOUD_TOKEN=${TOKEN}

# Upload image
packer init .
packer build .
# Save the image ID
export IMAGE_ID=<image-id-in-packer-output>
```

After doing this, you can find the snapshot in the console interface.

## Creating a Cluster via the CLI

This section assumes you have the [hcloud console utility](https://community.hetzner.com/tutorials/howto-hcloud-cli) on your local machine.

```bash theme={null}
# Set hcloud context and api key
hcloud context create talos-tutorial
```

### Create a Load Balancer

Create a load balancer by issuing the commands shown below.
Save the IP/DNS name, as this info will be used in the next step.

```bash theme={null}
hcloud load-balancer create --name controlplane --network-zone eu-central --type lb11 --label 'type=controlplane'

### Result is like:
# LoadBalancer 484487 created
# IPv4: 49.12.X.X
# IPv6: 2a01:4f8:X:X::1

hcloud load-balancer add-service controlplane \
    --listen-port 6443 --destination-port 6443 --protocol tcp
hcloud load-balancer add-target controlplane \
    --label-selector 'type=controlplane'
```

### Create the Machine Configuration Files

#### Generating Base Configurations

Using the IP/DNS name of the loadbalancer created earlier, generate the base configuration files for the Talos machines by issuing:

```bash theme={null}
$ talosctl gen config talos-k8s-hcloud-tutorial https://<load balancer IP or DNS>:6443
created controlplane.yaml
created worker.yaml
created talosconfig
```

At this point, you can modify the generated configs to your liking.
Optionally, you can specify [machine configuration patches](../../configure-your-talos-cluster/system-configuration/patching#configuration-patching-with-talosctl-cli) which will be applied during the config generation.

#### Validate the Configuration Files

Validate any edited machine configs with:

```bash theme={null}
$ talosctl validate --config controlplane.yaml --mode cloud
controlplane.yaml is valid for cloud mode
$ talosctl validate --config worker.yaml --mode cloud
worker.yaml is valid for cloud mode
```

### Create the Servers

We can now create our servers.
Note that you can find `IMAGE_ID` in the snapshot section of the console: `https://console.hetzner.cloud/projects/$PROJECT_ID/servers/snapshots`.

#### Create the Control Plane Nodes

Create the control plane nodes with:

```bash theme={null}
export IMAGE_ID=<your-image-id>

hcloud server create --name talos-control-plane-1 \
    --image ${IMAGE_ID} \
    --type cx21 --location hel1 \
    --label 'type=controlplane' \
    --user-data-from-file controlplane.yaml

hcloud server create --name talos-control-plane-2 \
    --image ${IMAGE_ID} \
    --type cx21 --location fsn1 \
    --label 'type=controlplane' \
    --user-data-from-file controlplane.yaml

hcloud server create --name talos-control-plane-3 \
    --image ${IMAGE_ID} \
    --type cx21 --location nbg1 \
    --label 'type=controlplane' \
    --user-data-from-file controlplane.yaml
```

#### Create the Worker Nodes

Create the worker nodes with the following command, repeating (and incrementing the name counter) as many times as desired.

```bash theme={null}
hcloud server create --name talos-worker-1 \
    --image ${IMAGE_ID} \
    --type cx21 --location hel1 \
    --label 'type=worker' \
    --user-data-from-file worker.yaml
```

### Bootstrap Etcd

To configure `talosctl` we will need the first control plane node's IP.
This can be found by issuing:

```bash theme={null}
hcloud server list | grep talos-control-plane
```

Set the `endpoints` and `nodes` for your talosconfig with:

```bash theme={null}
talosctl --talosconfig talosconfig config endpoint <control-plane-1-IP>
talosctl --talosconfig talosconfig config node <control-plane-1-IP>
```

Bootstrap `etcd` on the first control plane node with:

```bash theme={null}
talosctl --talosconfig talosconfig bootstrap
```

### Retrieve the `kubeconfig`

At this point we can retrieve the admin `kubeconfig` by running:

```bash theme={null}
talosctl --talosconfig talosconfig kubeconfig .
```
