How To Create Hetzner Server with Terraform

Hetzner is one of many provider that had official terraform provider, by using terraform it easy to deploy many server with less code and without touching the UI. After we learn about this we can provision the server less than one minute, which save time for big project.

Each terraform provider comes with their own implementation, read the official documentation before start writing the code or just follow the tutorial here 🙂

Create SSH Key

We’ll use ssh key to login to server automatically, so we don’t need to generate any password, it seamless

ssh-keygen -t rsa -b 4096
# output
jack~$ ssh-keygen -t rsa -b 4096
Generating public/private rsa key pair.
Enter file in which to save the key (/home/jack/.ssh/id_rsa): 
Created directory '/home/jack/.ssh'.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/jack/.ssh/id_rsa
Your public key has been saved in /home/jack/.ssh/id_rsa.pub
The key fingerprint is:
SHA256:zU3WWOpMxE1qJJniqVpt8EperP4Vr2olSLJ+RLw9uWs jack@server-0
The key's randomart image is:
+---[RSA 4096]----+
|          .+ooo  |
|        . o+.*.  |
|     . . o  O .  |
|    . = oo O     |
|     = XS.+ +    |
|    . B @ .o     |
|   . * = =. .    |
|    o = E. .     |
|     o.++o.      |
+----[SHA256]-----+

we’ll copy id_rsa.pub to any server that we’ll provision by terraform.

Create Hetzner API Token

Go to Hetzner Console, https://console.hetzner.cloud/projects/{PROJECT_ID}/security/tokens. Create a read/write token
generate new token for terraform
make sure to copy the token value, because it’ll only shown once.
copy the api token

Terraform Files

Before write any code, create a folder to store the files, lets call it hetzner-app-server

mkdir hetzner-app-server

The file structure

hetzner-app-server
├── provider.tf
├── server.tf
├── ssh.tf
└── variable.tf

provider.tf for provider configurations
server.tf for server configurations
ssh.tf for ssh related configurations
variable.tf central places for variable configurations

After knowing that we’re going to code the configuration for each files, refer to the official hetzner terraform for references. We’ll create server CP22 in Falkenstein location.
Create a provider.tf file with following contents

terraform {
  required_providers {
    hcloud = {
      source  = "hetznercloud/hcloud"
      version = "~> 1.49"
    }
  }
}
 
provider "hcloud" {
  token = var.HCLOUD_TOKEN
}

Create a server.tf file with following contents

resource "hcloud_server" "appserver" {
  count                      = var.instances
  name                       = "appserver-${count.index}"
  image                      = var.os_type
  server_type                = var.server_type
  location                   = var.location
  ssh_keys                   = [hcloud_ssh_key.default.name]
  allow_deprecated_images    = false
  shutdown_before_deletion   = false
  backups                    = false
  ignore_remote_firewall_ids = false
  rebuild_protection         = false
  delete_protection          = false
  keep_disk                  = true
  placement_group_id         = hcloud_placement_group.appserver.id
  public_net {
    ipv4_enabled = true
    ipv6_enabled = false
  }
  labels = {
    type = "appserver"
  }
 
  provisioner "local-exec" {
    command = "echo ${self.name} : ${self.ipv4_address} >> server-ips.txt"
  }
 
}
 
resource "hcloud_placement_group" "appserver" {
  name = "placement-group-appserver"
  type = "spread"
  labels = {
    key = "appserver"
  }
}

in the project folder we’ll have server-ips.txt where we can find the server public IP

Create a ssh.tf file with following contents

resource "hcloud_ssh_key" "default" {
  name       = "Public Key"
  public_key = file("~/.ssh/id_rsa.pub")
}

Create a variable.tf file with following contents

variable "HCLOUD_TOKEN" {}
 
variable "location" {
  default = "fsn1"
}
 
variable "instances" {
  default = "1"
}
 
variable "server_type" {
  default = "cx22"
}
 
variable "os_type" {
  default = "debian-12"
}

Run Terraform

in the terminal, we’ll create a new environment variable HCLOUD_TOKEN, the token will be more secure and not included in the terraform files directly

export TF_VAR_HCLOUD_TOKEN=XXXXXXXXXXXXXXXXX

TF_VAR_ is the identifier for Terraform, it’ll only use the values after that string, in this case HCLOUD_TOKEN, that the reason we’ve var.HCLOUD_TOKEN in provider.tf

For the first time, we’ll initiate the terraform, go to terraform folder then run terraform init

cd hetzner-app-server
terraform init

terraform init hetzner

to verify everything is good run

terraform plan

make sure you’re seeing ‘Note: You didn’t use the -out option to save this plan, so Terraform can’t guarantee to take exactly these actions if you run “terraform apply” now.’ at the of output from those command.

Now, let’s provisioning the server

terraform apply -auto-approve

terraform success deployed
If we’re go to Hetzner dashboard, we’ll see something similiar to screenshot below
server created in hetzner UI
From screenshot above we can see the server public IP or you can check server-ips.txt file

Now try to login to the server

ssh root@IP-SERVER

Delete the Server

If you’re willing to delete or destroy the server, run

terraform apply -destroy

be careful with that command, it’ll destroy all config and server that we have created using previous terraform command.

Leave a Comment