2025-12-27 13:48:42 +01:00
|
|
|
# Provider Configuration
|
|
|
|
|
provider "hcloud" {
|
|
|
|
|
token = var.hcloud_token
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-05 16:40:37 +01:00
|
|
|
# hcloud provider handles both Cloud and DNS resources
|
2025-12-27 13:48:42 +01:00
|
|
|
|
2026-01-17 19:50:30 +01:00
|
|
|
# Per-Client SSH Keys
|
|
|
|
|
resource "hcloud_ssh_key" "client" {
|
|
|
|
|
for_each = var.clients
|
|
|
|
|
name = "client-${each.key}-deploy-key"
|
|
|
|
|
public_key = file("${path.module}/../keys/ssh/${each.key}.pub")
|
2025-12-27 13:48:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Firewall Rules
|
|
|
|
|
resource "hcloud_firewall" "client_firewall" {
|
|
|
|
|
name = "client-default-firewall"
|
|
|
|
|
|
|
|
|
|
# SSH (restricted - add your management IPs here)
|
|
|
|
|
rule {
|
|
|
|
|
direction = "in"
|
|
|
|
|
protocol = "tcp"
|
|
|
|
|
port = "22"
|
|
|
|
|
source_ips = [
|
|
|
|
|
"0.0.0.0/0", # CHANGE THIS: Replace with your management IP
|
|
|
|
|
"::/0"
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# HTTP (for Let's Encrypt challenge)
|
|
|
|
|
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"
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Client VPS Instances
|
|
|
|
|
resource "hcloud_server" "client" {
|
|
|
|
|
for_each = var.clients
|
|
|
|
|
|
|
|
|
|
name = each.key
|
|
|
|
|
server_type = each.value.server_type
|
|
|
|
|
image = "ubuntu-24.04"
|
|
|
|
|
location = each.value.location
|
2026-01-17 19:50:30 +01:00
|
|
|
ssh_keys = [hcloud_ssh_key.client[each.key].id]
|
2025-12-27 13:48:42 +01:00
|
|
|
firewall_ids = [hcloud_firewall.client_firewall.id]
|
|
|
|
|
|
|
|
|
|
labels = {
|
|
|
|
|
client = each.key
|
|
|
|
|
role = "app-server"
|
|
|
|
|
# Note: labels can't contain special chars, store apps list separately if needed
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Enable backups if requested
|
|
|
|
|
backups = var.enable_snapshots
|
|
|
|
|
|
2026-01-20 19:06:19 +01:00
|
|
|
# Public network configuration (can be disabled for private-only servers)
|
|
|
|
|
public_net {
|
|
|
|
|
ipv4_enabled = lookup(each.value, "public_ip_enabled", true)
|
|
|
|
|
ipv6_enabled = lookup(each.value, "public_ip_enabled", true)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Private network (required for servers without public IP)
|
|
|
|
|
dynamic "network" {
|
|
|
|
|
for_each = lookup(each.value, "private_ip", null) != null ? [1] : []
|
|
|
|
|
content {
|
|
|
|
|
network_id = hcloud_network.private.id
|
|
|
|
|
ip = each.value.private_ip
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-27 13:48:42 +01:00
|
|
|
# User data for initial setup
|
2026-01-20 19:06:19 +01:00
|
|
|
user_data = lookup(each.value, "public_ip_enabled", true) == false ? templatefile("${path.module}/user-data-private.yml", {
|
|
|
|
|
hostname = each.key
|
|
|
|
|
}) : templatefile("${path.module}/user-data-public.yml", {
|
|
|
|
|
hostname = each.key
|
|
|
|
|
})
|
2025-12-27 13:48:42 +01:00
|
|
|
}
|