Hetzner Cloud con Terraform: Infrastruttura a Basso Costo
Tutorial pratico per gestire Hetzner Cloud con Terraform. Server, network, firewall, load balancer. Esempi di codice pronti all'uso.
Hetzner e diventato il mio cloud provider preferito per progetti personali e startup. I prezzi sono imbattibili — un server con 2 vCPU, 4GB RAM, 40GB SSD costa circa 4€/mese. Confrontalo con AWS o GCP e capisci perche e interessante.
Ma Hetzner senza automazione e gestione manuale. Terraform risolve questo problema. Vediamo come usarli insieme.
Perche Hetzner
Prima di entrare nel Terraform, due parole su perche Hetzner.
Prezzi. Drasticamente piu bassi dei big cloud. Non del 10-20%, del 50-80% in meno. Per workload che non richiedono servizi managed specifici di AWS/GCP, il risparmio e significativo.
Performance. Server fisici in data center europei (Germania, Finlandia). Rete veloce, storage SSD/NVMe. Non sono server scrausi, sono macchine serie.
Semplicita. Meno servizi dei big cloud, ma quelli che ci sono funzionano bene. Server, volume, network, load balancer, firewall, DNS. Il necessario per la maggior parte dei casi.
Limiti. Meno region (Europa principalmente, US da poco), meno servizi managed, meno integrazioni. Se hai bisogno di Lambda, DynamoDB, o servizi specifici AWS, Hetzner non fa per te.
Setup Iniziale
API Token
Vai su Hetzner Cloud Console, crea un progetto, genera un API token con permessi Read & Write.
Provider Terraform
# versions.tf
terraform {
required_providers {
hcloud = {
source = "hetznercloud/hcloud"
version = "~> 1.45"
}
}
required_version = ">= 1.0"
}
# provider.tf
provider "hcloud" {
token = var.hcloud_token
}
# variables.tf
variable "hcloud_token" {
description = "Hetzner Cloud API Token"
type = string
sensitive = true
}
Il token va passato come variabile, non hardcodato. Usa un file .tfvars (non committare!) o variabili d'ambiente:
export TF_VAR_hcloud_token="your-token-here"
Il Primo Server
Creiamo un server base:
# server.tf
resource "hcloud_server" "web" {
name = "web-server"
image = "ubuntu-22.04"
server_type = "cx22" # 2 vCPU, 4GB RAM
location = "fsn1" # Falkenstein, Germany
ssh_keys = [hcloud_ssh_key.default.id]
labels = {
environment = "production"
role = "web"
}
}
resource "hcloud_ssh_key" "default" {
name = "default"
public_key = file("~/.ssh/id_rsa.pub")
}
output "server_ip" {
value = hcloud_server.web.ipv4_address
}
terraform init
terraform plan
terraform apply
In un minuto hai un server running. L'output ti da l'IP per connetterti via SSH.
Tipi di Server
Hetzner ha diverse linee:
- CX — Shared vCPU, economici, buoni per la maggior parte degli usi
- CPX — Shared vCPU AMD, stesse performance a prezzi simili
- CCX — Dedicated vCPU, per workload che richiedono performance costanti
- CAX — ARM (Ampere), ottimo rapporto prezzo/performance
Per uso generale, cx22 (4€/mese) o cx32 (8€/mese) sono ottimi punti di partenza.
Network Privato
Per comunicazione tra server senza passare da internet:
# network.tf
resource "hcloud_network" "private" {
name = "private-network"
ip_range = "10.0.0.0/16"
}
resource "hcloud_network_subnet" "subnet" {
network_id = hcloud_network.private.id
type = "cloud"
network_zone = "eu-central"
ip_range = "10.0.1.0/24"
}
# Collega il server alla rete privata
resource "hcloud_server_network" "web_network" {
server_id = hcloud_server.web.id
network_id = hcloud_network.private.id
ip = "10.0.1.10"
}
I server sulla stessa rete privata comunicano senza costi di traffico e con latenza minima.
Firewall
Hetzner ha firewall gestiti a livello di progetto:
# firewall.tf
resource "hcloud_firewall" "web" {
name = "web-firewall"
# SSH
rule {
direction = "in"
protocol = "tcp"
port = "22"
source_ips = [
"0.0.0.0/0",
"::/0"
]
}
# HTTP
rule {
direction = "in"
protocol = "tcp"
port = "80"
source_ips = [
"0.0.0.0/0",
"::/0"
]
}
# HTTPS
rule {
direction = "in"
protocol = "tcp"
port = "443"
source_ips = [
"0.0.0.0/0",
"::/0"
]
}
}
# Applica il firewall al server
resource "hcloud_firewall_attachment" "web_fw" {
firewall_id = hcloud_firewall.web.id
server_ids = [hcloud_server.web.id]
}
Di default tutto il traffico in ingresso e bloccato. Apri solo quello che serve.
Volume Storage
Per storage persistente separato dal server:
# volume.tf
resource "hcloud_volume" "data" {
name = "data-volume"
size = 50 # GB
location = "fsn1"
format = "ext4"
}
resource "hcloud_volume_attachment" "data_attachment" {
volume_id = hcloud_volume.data.id
server_id = hcloud_server.web.id
automount = true
}
Il volume viene montato automaticamente. Se il server muore, i dati sul volume restano.
Load Balancer
Per distribuire traffico su piu server:
# load_balancer.tf
resource "hcloud_load_balancer" "web_lb" {
name = "web-lb"
load_balancer_type = "lb11"
location = "fsn1"
}
resource "hcloud_load_balancer_network" "lb_network" {
load_balancer_id = hcloud_load_balancer.web_lb.id
network_id = hcloud_network.private.id
ip = "10.0.1.1"
}
resource "hcloud_load_balancer_service" "http" {
load_balancer_id = hcloud_load_balancer.web_lb.id
protocol = "http"
listen_port = 80
destination_port = 80
health_check {
protocol = "http"
port = 80
interval = 10
timeout = 5
retries = 3
http {
path = "/health"
status_codes = ["200"]
}
}
}
resource "hcloud_load_balancer_target" "web_target" {
load_balancer_id = hcloud_load_balancer.web_lb.id
type = "server"
server_id = hcloud_server.web.id
use_private_ip = true
}
output "lb_ip" {
value = hcloud_load_balancer.web_lb.ipv4
}
Il load balancer costa circa 5€/mese. Se hai traffico significativo o vuoi HA, vale la pena.
Cloud-init per Configurazione
Invece di configurare manualmente i server, usa cloud-init:
# server_with_cloudinit.tf
resource "hcloud_server" "app" {
name = "app-server"
image = "ubuntu-22.04"
server_type = "cx22"
location = "fsn1"
ssh_keys = [hcloud_ssh_key.default.id]
user_data = <<-EOF
#cloud-config
package_update: true
packages:
- docker.io
- docker-compose
runcmd:
- systemctl enable docker
- systemctl start docker
- usermod -aG docker ubuntu
write_files:
- path: /etc/environment
content: |
ENVIRONMENT=production
EOF
}
Al primo boot, il server installa Docker e configura l'ambiente. Niente SSH manuale.
Gestione dello State
Per progetti seri, non tenere lo state locale.
S3 Backend (con Hetzner Object Storage)
Hetzner ha object storage S3-compatibile:
terraform {
backend "s3" {
bucket = "terraform-state"
key = "hetzner/terraform.tfstate"
region = "eu-central-1"
endpoint = "https://fsn1.your-objectstorage.com"
skip_credentials_validation = true
skip_metadata_api_check = true
skip_region_validation = true
}
}
Terraform Cloud
Alternativa gratuita per team piccoli:
terraform {
cloud {
organization = "your-org"
workspaces {
name = "hetzner-production"
}
}
}
Tips e Best Practices
Usa location diverse per HA. Hetzner ha data center a Falkenstein (fsn1), Nuremberg (nbg1), Helsinki (hel1), e US (ash, hil). Distribuisci per fault tolerance.
Snapshot prima di modifiche rischiose. Hetzner supporta snapshot di server. Falli prima di upgrade importanti.
Monitora i costi. Hetzner e economico, ma i costi si accumulano. Usa i label per tracciare chi usa cosa.
Considera ARM. I server CAX (ARM) hanno rapporto prezzo/performance eccellente. Se il tuo software supporta ARM, valutali.
Terraform state locking. Se lavori in team, assicurati che il backend supporti locking per evitare conflitti.
Conclusione
Hetzner + Terraform e una combinazione potente per chi vuole infrastruttura cloud senza spendere una fortuna. I limiti ci sono (meno servizi managed, meno region), ma per molti casi d'uso non sono un problema.
Se stai pagando centinaia di euro al mese su AWS per server che potrebbero girare su Hetzner, fai due conti. Il risparmio puo essere significativo, e con Terraform la gestione non e piu complicata.
Non e per tutti. Se hai bisogno di servizi specifici AWS/GCP, resta li. Ma se hai bisogno principalmente di server, rete, e storage, Hetzner e un'opzione che vale la pena considerare.
Il cloud migliore e quello che risolve il tuo problema al costo giusto. A volte non e il piu grande.