############################################################################### # main.tf — KrustyPlanet VPS on Hetzner Cloud # Stack: Hetzner Cloud + Ubuntu 24.04 + nginx + contact-api + SSL ############################################################################### terraform { required_version = ">= 1.6.0" required_providers { hcloud = { source = "hetznercloud/hcloud" version = "~> 1.47" } } } provider "hcloud" { token = var.hcloud_token } ############################################################################### # SSH Key ############################################################################### resource "hcloud_ssh_key" "krustyplanet" { name = "${var.project_name}-key" public_key = var.ssh_public_key } ############################################################################### # Network (private) ############################################################################### resource "hcloud_network" "krustyplanet" { name = "${var.project_name}-network" ip_range = "10.0.0.0/16" } resource "hcloud_network_subnet" "krustyplanet" { network_id = hcloud_network.krustyplanet.id type = "cloud" network_zone = var.network_zone ip_range = "10.0.1.0/24" } ############################################################################### # Firewall ############################################################################### resource "hcloud_firewall" "krustyplanet" { name = "${var.project_name}-firewall" # SSH admin — always restricted to your IPs rule { direction = "in" protocol = "tcp" port = "22" source_ips = var.ssh_allowed_ips } # 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"] } # Apply to the server apply_to { server = hcloud_server.krustyplanet.id } } ############################################################################### # Server ############################################################################### resource "hcloud_server" "krustyplanet" { name = "${var.project_name}-server" server_type = var.server_type image = "ubuntu-24.04" location = var.location ssh_keys = [hcloud_ssh_key.krustyplanet.id] network { network_id = hcloud_network.krustyplanet.id ip = "10.0.1.10" } user_data = templatefile("${path.module}/cloud-init.yaml.tpl", { project_name = var.project_name node_version = var.node_version domain = var.domain }) labels = { project = var.project_name role = "web" } depends_on = [hcloud_network_subnet.krustyplanet] } ############################################################################### # Floating IP (stable public IP across rebuilds) ############################################################################### resource "hcloud_floating_ip" "krustyplanet" { type = "ipv4" home_location = var.location description = "${var.project_name} floating IP" } resource "hcloud_floating_ip_assignment" "krustyplanet" { floating_ip_id = hcloud_floating_ip.krustyplanet.id server_id = hcloud_server.krustyplanet.id } ############################################################################### # Volume (persistent data — survives server rebuilds) ############################################################################### resource "hcloud_volume" "krustyplanet_data" { name = "${var.project_name}-data" size = var.volume_size_gb location = var.location format = "ext4" } resource "hcloud_volume_attachment" "krustyplanet_data" { volume_id = hcloud_volume.krustyplanet_data.id server_id = hcloud_server.krustyplanet.id automount = true }